【问题标题】:How to read until EOF from cin in C++如何在 C++ 中从 cin 读取直到 EOF
【发布时间】:2010-09-17 03:36:07
【问题描述】:

我正在编写一个直接从用户输入读取数据的程序,并且想知道如何(没有循环)从标准输入读取所有数据,直到 EOF。我正在考虑使用cin.get( input, '\0' ),但'\0' 并不是真正的EOF 字符,它只会读取到EOF 或'\0',以先到者为准。

或者使用循环是唯一的方法?如果是这样,最好的方法是什么?

【问题讨论】:

    标签: c++ input iostream


    【解决方案1】:

    stdin 读取可变数量数据的唯一方法是使用循环。我一直发现std::getline() 函数效果很好:

    std::string line;
    while (std::getline(std::cin, line))
    {
        std::cout << line << std::endl;
    }
    

    默认情况下,getline() 会一直读取到换行符。您可以指定替代终止字符,但 EOF 本身不是字符,因此您不能简单地调用 getline()

    【讨论】:

    • 这里要注意的是,当您从通过标准输入管道输入的文件中读取时,这个和给出的大多数答案都会在您的末尾附加一个额外的换行符输入。并非所有文件都以换行符结尾,但循环的每次迭代都会将“std::endl”附加到流中。在大多数情况下,这可能不是问题,但如果文件完整性是一个问题,这可能会再次困扰您。
    • 这不应该是最受好评的答案。请参阅以下社区 wiki 答案。另外,也许看到这个问题:stackoverflow.com/questions/3203452/…
    【解决方案2】:

    使用循环:

    #include <iostream>
    using namespace std;
    ...
    // numbers
    int n;
    while (cin >> n)
    {
       ...
    }
    // lines
    string line;
    while (getline(cin, line))
    {
       ...
    }
    // characters
    char c;
    while (cin.get(c))
    {
       ...
    }
    

    resource

    【讨论】:

      【解决方案3】:

      您可以使用流迭代器在没有显式循环的情况下做到这一点。我确信它在内部使用了某种循环。

      #include <string>
      #include <iostream>
      #include <istream>
      #include <ostream>
      #include <iterator>
      
      int main()
      {
      // don't skip the whitespace while reading
        std::cin >> std::noskipws;
      
      // use stream iterators to copy the stream to a string
        std::istream_iterator<char> it(std::cin);
        std::istream_iterator<char> end;
        std::string results(it, end);
      
        std::cout << results;
      }
      

      【讨论】:

      • 不错。至于“我确定它在内部使用某种循环”-任何解决方案都可以。
      • 这似乎会从输入中删除换行符,即使它们出现在中间。
      【解决方案4】:

      在使用std::istream_iterator研究了KeithB的解决方案后,我发现了std:istreambuf_iterator

      测试程序将所有管道输入读入一个字符串,然后再次写出:

      #include <iostream>
      #include <iterator>
      #include <string>
      
      int main()
      {
        std::istreambuf_iterator<char> begin(std::cin), end;
        std::string s(begin, end);
        std::cout << s;
      }
      

      【讨论】:

      • 这应该是规范的答案。
      • 投反对票。那么与 KeithB 的解决方案相比有哪些优缺点呢?是的,您使用的是std::istreambuf_iterator 而不是std::istream_iterator,但这是为了什么?
      • std::istreambuf_iterator 默认跳过空白,可以更快
      【解决方案5】:

      可能最简单且通常有效:

      #include <iostream>
      int main()
      {
          std::cout << std::cin.rdbuf();
      }
      

      如果需要,这里使用std::ostringstream等其他类型的流作为缓冲区,而不是标准输出流。

      【讨论】:

      • 你们已经知道了,但可能对某些人有帮助:std::ostringstream std_input; std_input &lt;&lt; std::cin.rdbuf(); std::string s = std_input.str()s 中有所有输入(如果输入太大,请注意 std::string
      【解决方案6】:

      悲伤的旁注:我决定使用 C++ IO 来与基于 boost 的代码保持一致。从这个问题的答案中,我选择了while (std::getline(std::cin, line))。在 cygwin (mintty) 中使用 g++ 版本 4.5.3 (-O3) 我得到了 2 MB/s 的吞吐量。 Microsoft Visual C++ 2010 (/O2) 使相同代码的速度达到 40 MB/s。

      在将 IO 重写为纯 C while (fgets(buf, 100, stdin)) 后,两个测试编译器的吞吐量都跃升至 90 MB/s。这对于任何大于 10 MB 的输入都会有所不同...

      【讨论】:

      • 无需将代码重写为纯 C,只需在 while 循环之前添加 std::ios::sync_with_stdio(false);cin.tie(NULL); 如果您将阅读和写作交错,也可能会有所帮助。
      【解决方案7】:

      您可以使用std::istream::getline()(或者最好是version that works on std::string)函数来获取整行。两者都有允许您指定分隔符(行尾字符)的版本。字符串版本的默认值为 '\n'。

      【讨论】:

        【解决方案8】:
        while(std::cin) {
         // do something
        }
        

        【讨论】:

        • 这是一个可怕的答案灾难,因为它几乎肯定会导致错误的代码。
        • @KerrekSB 为什么几乎肯定会导致错误代码?
        • @MatúšFerech:因为它强烈建议// do something不包含对I/O操作返回值的额外检查,它包含的检查是没有意义的。
        【解决方案9】:

        等等,我理解正确吗?您正在使用 cin 进行键盘输入,并且您想在用户输入 EOF 字符时停止读取输入?为什么用户会输入 EOF 字符?还是您的意思是您想在 EOF 停止读取文件?

        如果您实际上是在尝试使用 cin 来读取 EOF 字符,那么为什么不将 EOF 指定为分隔符呢?

        // Needed headers: iostream
        
        char buffer[256];
        cin.get( buffer, '\x1A' );
        

        如果您要在 EOF 处停止读取文件,则只需使用 getline 并再次将 EOF 指定为分隔符。

        // Needed headers: iostream, string, and fstream
        
        string buffer;
        
            ifstream fin;
            fin.open("test.txt");
            if(fin.is_open()) {
                getline(fin,buffer,'\x1A');
        
                fin.close();
            }
        

        【讨论】:

          【解决方案10】:

          一种选择是使用容器,例如

          std::vector<char> data;
          

          重定向所有输入到这个集合,直到收到EOF,即

          std::copy(std::istream_iterator<char>(std::cin),
              std::istream_iterator<char>(),
              std::back_inserter(data));
          

          但是,使用过的容器可能需要过于频繁地重新分配内存,或者当您的系统内存不足时,您会以 std::bad_alloc 异常结束。为了解决这些问题,您可以保留固定数量的N 元素并单独处理这些数量的元素,即

          data.reserve(N);    
          while (/*some condition is met*/)
          {
              std::copy_n(std::istream_iterator<char>(std::cin),
                  N,
                  std::back_inserter(data));
          
              /* process data */
          
              data.clear();
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-10-24
            • 2011-04-15
            • 1970-01-01
            • 2012-12-22
            • 2017-08-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多