从std :: ifstream阻塞读取

4
我正在使用std::ifstream::read从管道(Linux)或类似管道设备对象(Windows)中读取数据。 然而,当没有更多数据时,read会读取0字节并设置EOF。 是否有办法从ifstream进行阻塞读取,只有在有更多数据时才返回?
我不想忙等待EOF标志清除。
如果C++标准库无法实现,最接近的其他选项是什么? 我可以用纯C吗,还是必须诉诸于特定于操作系统的API?
2个回答

3

不幸的是,std 在任何非算法功能上都非常薄弱,比如IO。你总是需要依赖第三方解决方案。幸运的是,有Boost,如果你不介意的话,我建议使用它来减少特定于操作系统的代码。

    namespace bs = boost::iostreams;
    int fd; // Create, for example, Posix file descriptor and specify necessary flags for it.
    bs::file_descriptor_source fds(fd);
    bs::stream<bs::file_descriptor_source> stream(fds);
    // Work with the stream as it is std stream

在这个小例子中,我使用了Boost IO Streams,特别是file_descriptor_source,它作为一个底层流设备,隐藏了Windows或Posix特定的管道。你可以自己打开管道,因此可以根据需要配置管道。

谢谢,我会尝试一下。不幸的是,在Windows上安装Boost几乎和从一开始就使用WinApi编写它一样复杂 ;-). - jdm
如果您正在使用MinGW,可以使用packman根据此软件包存储库Alexpux Packages进行安装。 - Yuki
1
对于Visual Studio,可以使用这些二进制文件 - Yuki

1

好像没有办法进行阻塞读取。清除错误位也无济于事。只有重新打开FIFO,就像这个例子一样:

int main(int argc, char **argv)
{
    int rc=0;
    enum FATAL {ERR_ARGV,ERR_OPEN_FILE};
    try
    {
            if( argv[1] == NULL) throw ERR_ARGV;
            std::ifstream fifo;

            while(1)
            {
                    fifo.open(argv[1],std::ifstream::in);
                    if( !fifo.is_open() ) throw ERR_OPEN_FILE;

                    std::string line;
                    while(std::getline(fifo,line))
                    {
                            std::cout << line << "\n"; fflush(stdout);
                    }
                    fifo.close();
            }
            // never should come here
    }
    catch(FATAL e)
    {
            rc=e;
            switch(e)
            {
            case ERR_ARGV:
                    std::cerr << "ERROR: argument 1 should be a fifo file name\n";
                    break;
            case ERR_OPEN_FILE:
                    std::cerr << "ERROR: unabel to open file " << argv[1] << "\n";
                    break;
            }
    }
    return(rc);
}

我已经测试了这段代码,它可以从FIFO中进行无限读取,并且运行正常。


清除错误位不会有帮助是什么意思?我可以正常调用 input.clear(),但之后无法从中读取数据,接下来的读取尝试会再次设置 EOF 位。这正常吗?...你的解决方案听起来不错,但是���管道关闭时,我的服务器当前正在重置其状态,我必须先更改它。 - jdm
是的,这似乎很正常。问题在于您无法以std :: getline()或其他读取函数会再次阻塞的方式重置状态,就像在打开fifo之后一样:(好吧,是的,管道的另一端也应该重新打开(在这种情况下是服务器)。 - 0x0C4

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