如何在Qt中读取标准输入直到结束?

4

我有一个Qt应用程序,可以通过以下方式调用:

cat bla.bin  | myapp

如何在Win、Mac和Linux上最简单地将整个输入(stdin)读入QByteArray?

我尝试了几种方法,但它们似乎都不能在Windows上正常工作:

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QByteArray content;

    //---Test 1: hangs forever, reads 0
    while(!std::cin.eof()) {
        char arr[1024];
        int s = std::cin.readsome(arr,sizeof(arr));
        content.append(arr,s);
    }

    //---Test 2: Runs into timeout
    QFile in;
    if(!in.open(stdin,QFile::ReadOnly|QFile::Unbuffered)) {
        qDebug() << in.errorString();
    }
    while (in.waitForReadyRead(1000)) {
        content+=in.readAll();
    }
    in.close();

    return app.exec();
}

我是否遇到了事件循环问题?或者不需要它也能正常工作吗?

我是否遇到了事件循环问题?很可能是的。因为事件循环在app.exec();之后启动。尝试在文件关闭之前读取或在调用exec之后移动读取。 - Lol4t0
不要那样使用QFileQFile永远不会报告“ready read”。使用std::cin的方法应该在任何地方都可以工作,你是否在Windows下编译时使用了CONFIG+=console - peppe
根据文档,我不需要事件循环。是的,我的.pro文件中有CONFIG+=console和CONFIG-=app_bundle。在Linux上也无法工作。 - Timo
1个回答

4
实际从stdin读取的主要问题源于使用readsome。通常不使用readsome来读取文件(包括stdin)。readsome通常用于异步源上的二进制数据。从技术上讲,readsome不会设置eof。在这方面,read是不同的,因为它将相应地设置eof。这里有一个SO问题/答案here可能会引起兴趣。如果您支持Linux和Windows并且正在读取stdin,则必须注意,在Windows上stdin未以二进制模式打开(stdout也是如此)。在Windows上,您必须在stdin上使用_setmode。一种方法是使用#ifdef使用Q_OS_WIN32。使用QFile无法解决此问题。
在你尝试创建的代码中,似乎并没有考虑实际上需要事件循环。即使没有事件循环,你仍然可以使用QT对象,如QByteArray。在你的代码中,你从stdin(cin)读取数据,然后执行了return app.exec();,将控制台应用程序放入等待事件的循环中。在app.exec();之前,你没有向QT事件队列添加任何事件,因此你只能使用control-c结束应用程序。如果不需要事件循环,则可以使用以下代码:
#include <QCoreApplication>
#include <iostream>

#ifdef Q_OS_WIN32
#include <fcntl.h>
#include <io.h>
#endif

int main()
{
    QByteArray content;

#ifdef Q_OS_WIN32
    _setmode(_fileno(stdin), _O_BINARY);
#endif

    while(!std::cin.eof()) {
        char arr[1024];
        std::cin.read(arr,sizeof(arr));
        int s = std::cin.gcount();
        content.append(arr,s);
    }
}

请注意我们使用了一个 QByteArray,但没有使用 QCoreApplication app(argc, argv); 和调用 app.exec();

1
在这里使用 QObject 任务是没有意义的,因为它会阻塞。 - Kuba hasn't forgotten Monica
你能展示一下这两个例子都没有产生原始 OP 所要求的结果吗?这些程序在这里运行的结果正如我所预期的那样。从 stdin 读取到 QByteArray 直到达到 EOF,然后优雅地退出应用程序。一个使用任务,另一个则完全避免了事件循环。 - Michael Petch
感谢您的回答。问题的重点更在于我无法读取stdin直到EOF,而不是整个Eventloop讨论。您提供的第一个示例似乎在Linux上可以工作,如果它在Windows上也可以工作,我会接受您的答案(我需要测试一下)。 - Timo
哦,你知道的,当我编写我的示例时,我甚至没有想到你正在使用readsome。我只是使用我知道有效的方法。readsome不适用于从文件(和stdin)中读取。它通常用于异步源上的二进制数据。从技术上讲,eof不会通过readsome设置。在这方面,read是不同的。这里有一个SO文章可能会感兴趣[链接](https://dev59.com/9Wox5IYBdhLWcg3weUCe)。 - Michael Petch
1
我会回答这个问题。你的"_setmode(_fileno(stdin), _O_BINARY);"解决了原始问题和修改后的问题。非常感谢。 - Timo
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接