如何读取stdin以qt结尾?

时间:2014-09-07 14:33:22

标签: c++ windows qt cross-platform

我有一个可以调用的qt-app:

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();
}

我遇到事件循环问题还是不应该没有?

1 个答案:

答案 0 :(得分:2)

实际从stdin阅读的主要问题源于使用readsomereadsome通常不用于读取文件(包括stdin)。 Readsome通常用于异步源上的二进制数据。从技术上讲,eof未设置readsomeread在这方面有所不同,因为它会相应地设置eof。有一个可能感兴趣的SO问题/答案here。如果您支持Linux和Windows并阅读stdin,则必须注意在Windows上stdin未以二进制模式打开(stdout也不是)。在Windows上,您必须在_setmode上使用stdin。一种方法是#ifdef使用Q_OS_WIN32。使用QFile无法解决此问题。

在您尝试创建它的代码中,您似乎对实际拥有事件循环感兴趣。您仍然可以在没有事件循环的情况下使用QByteArray等QT对象。在您的代码中,您从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();