【问题标题】:how to read stdin to end in qt?如何读取标准输入以在 qt 中结束?
【发布时间】:2014-09-07 14:33:21
【问题描述】:

我有一个可以调用的 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();
}

我是否遇到了事件循环问题,或者没有它就不能工作?

【问题讨论】:

  • Am I having a Event-Loop Problem? 可能。因为事件循环在app.exec(); 之后开始。尝试读取直到文件关闭或在调用exec 后移动读取
  • 不要那样使用QFileQFile 永远不会报告“已读”。 std::cin 的方法应该适用于任何地方,你是在 Windows 下使用CONFIG+=console 编译的吗?
  • 根据文档我不需要事件循环。是的,我的 .pro 文件中有 CONFIG+=console 和 CONFIG-=app_bundle。它也不适用于 linux。

标签: c++ windows qt cross-platform


【解决方案1】:

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

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

【讨论】:

  • 这里使用QObject 任务是没有意义的,因为它会阻塞。
  • 我在上面写了哪些代码块?第一个例子可能更接近原始海报的意图,没有事件循环。如果他想做一个事件循环,我生成的代码会执行他想要的任务,然后退出。它不会阻塞。这不是一个非常有用的例子,但它仍然按照他的要求做同样的事情。 OP 可能不知道如何让控制台应用程序处理事件并让它退出。
  • 你能证明这两个例子都没有产生原始 OP 所要求的吗?程序就像我预期的那样在这里运行。从标准输入读取到 QByteArray 直到到达 EOF,然后优雅地退出应用程序。一个使用任务,另一个完全避免事件循环。
  • 具体来说。 main() 将任务指定的一次性事件排队。 app.exec() 被执行。队列中唯一的偶数是我们的任务。 QT 执行run() 方法。 Task::Run() 读取标准输入直到 EOF,然后发出 finished 信号。 Finished 绑定到一个执行 quit() 的插槽。因此事件循环终止。控制离开 app.exec,程序退出作为回报。如果这个例子 blocks (其他阅读标准输入的地方)那么我希望你告诉我在哪里。我承认对于给出的示例,启动事件循环的 OP 是无用的。这是不必要的开销。
  • 我会回复这个问题。你的“_setmode(_fileno(stdin), _O_BINARY);”解决了原始问题和修改后的问题。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2017-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 2018-03-22
相关资源
最近更新 更多