【问题标题】:Repeatedly reading to EOF from stdin从标准输入重复读取 EOF
【发布时间】:2013-11-03 04:56:47
【问题描述】:

我希望我的程序从标准输入读取直到 EOF,打印所有输入,然后重复。我尝试清除 stdin 的 EOF 状态如下:

#include <string>
#include <iostream>
#include <iterator>

using namespace std;

int main() {

  cin >> noskipws;

  while (1) {

    printf("Begin");
    istream_iterator<char> iterator(cin);
    istream_iterator<char> end;
    string input(iterator, end);
    cout << input << endl;
    cin.clear();

  }

}

然而,在接收并打印第一个输入后,程序只是无限地打印“Begin”而不等待进一步的输入。

【问题讨论】:

  • 如何继续阅读 EOF 之后的内容?一旦没有更多数据,就没有更多数据了。
  • @JonathonReinhart EOF 并不一定意味着永远不会有更多数据,只是已经到达文件末尾。用户进入 EOF 转义后,终端可以继续提供输入,并且文件可以写入更多数据。
  • @hobbs 我明白这一点。我实际上考虑了您提到的内容,但想不出任何标准的 UNIX-y 程序在从标准输入获取 EOF 后继续尝试读取。如果我按 Ctrl+D,我希望它完成。
  • 最终我希望能够运行这个程序,输入一些跨越多行的输入,使用 Ctrl-D 发出 EOF 信号,并将我的输入转换为打印到标准输出。然后程序应该等待更多输入,然后是 EOF,然后打印到标准输出等。
  • @JonathonReinhart tail -f 理所当然地这样做(尽管通常不在标准输入上)。 perl - 从标准输入读取程序直到 EOF,然后将标准输入提供给程序以从中读取更多数据。他们是我唯一能想到的。无论如何,这当然是可能的。

标签: c++ io


【解决方案1】:

您在那里采用的方法不起作用 - 当 'cin' 在您使用的上下文中为您提供文件结尾时,cin 被关闭。

出于您声明的“读取文本直到 eof,然后再做一次”的目的,很抱歉之前错过了这一点的细微差别,但是如果您克隆标准输入文件描述符然后使用克隆,您可以继续从这些附加文件描述符中读取。

克隆 iostream 并不容易。见How to construct a c++ fstream from a POSIX file descriptor?

它有点像 c,但是这段代码会耗尽一个 stdin 的副本,直到该 stdin 关闭,然后它会制作一个新副本并耗尽它,然后继续。

#include <iostream>
#include <string>

void getInput(std::string& input)
{
    char buffer[4096];
    int newIn = dup(STDIN_FILENO);
    int result = EAGAIN;
    input = "";
    do {
        buffer[0] = 0;
        result = read(newIn, buffer, sizeof(buffer));
        if (result > 0)
            input += buffer;
    } while (result >= sizeof(buffer));
    close(newIn);

    return input;
}

int main(int argc, const char* argv[])
{
    std::string input;
    for (;;) {
        getInput(input);
        if (input.empty())
            break;
        std::cout << "8x --- start --- x8\n" << input.c_str() << "\n8x --- end --- x8\n\n";
    }
}

【讨论】:

    【解决方案2】:

    那是因为你有 printf("begin");在您的循环中,因此您将在每次循环时再次打印它。

    循环不会等待输入,因此每次从标准输入读取数据时 - 如果那里没有任何内容,它会立即获取 EOF 并继续循环,直到出现一些数据。

    如果这没有意义,或者我完全错了,请告诉我。

    例如:

    #include <string>
    #include <iostream>
    #include <iterator>
    
    using namespace std;
    
    int main() {
    
      cin >> noskipws;
    
      printf("Begin");
    
      while (1) {
    
        istream_iterator<char> iterator(cin);
        istream_iterator<char> end;
        string input(iterator, end);
        cout << input << endl;
        cin.clear();
    
      }
    
    }
    

    【讨论】:

    • 这个程序第一次执行时,循环体等待输入。我希望它在每次迭代中等待。将 print 语句移到循环之外并没有真正的帮助。仍然有写入 cout 的内容,它会向控制台打印无数个空白行,并清楚地表明循环没有等待。
    • 如果你想每次都写一行(比如问用户一个问题,然后他们输入一个答案,然后按回车键),那么也许使用 getline() 之类的东西可能会对你有所帮助。 cplusplus.com/reference/string/string/getline
    • 我希望输入跨越任意数量的行。
    • 这是有道理的,但你完全错了。您的解决方案仍然会造成无限循环。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-24
    • 2013-03-30
    • 2012-02-17
    相关资源
    最近更新 更多