【问题标题】:Non-blocking way to check if there is data on a iofstream检查 iofstream 上是否有数据的非阻塞方式
【发布时间】:2021-06-21 15:51:40
【问题描述】:

我需要一种方法来检查文件(fifo)上是否有数据要以非阻塞方式读取。 我试过使用peek;但它是阻塞的,我尝试get 然后unget 一个字符,以便在不更改内容的情况下检查文件;但是get 再次被阻止...

我发现的唯一非阻塞解决方案是使用std::getline(file, line_str) 并检查字符串是否为空;但是,这 适合我的需要,因为它会更改文件中的数据。 (数据是一个序列化的对象,一旦我检测到有要读取的内容,我就会读取)。

注意:我需要它是非阻塞的:我有多个文件流,需要定期检查所有文件流以查看是否有要读取/反序列化的对象。

这是我想要实现的一个简单示例:

Sender.cpp

#include <fstream>
#include <iostream>
#include <string>
extern "C"{
    #include <sys/stat.h>      // S_IRUSR, S_IWUSR, mkfifo
}
#include <cerrno>              // errno

int main(int, char** argv) {
    std::string pipe = "foobar";
    if(mkfifo(pipe.c_str(), S_IRUSR | S_IWUSR) < 0){
        if (errno != EEXIST){
            std::cerr << errno;
        }
    }
    std::ofstream file{pipe.c_str()};
    file.write("boop", 4); // Simulated object serialization

}

Reader.cpp

#include <fstream>
#include <iostream>
#include <string>
extern "C"{
    #include <sys/stat.h>      // S_IRUSR, S_IWUSR, mkfifo
}
#include <cerrno>              // errno

int main(int, char** argv) {
    std::string pipe = "foobar";
    if(mkfifo(pipe.c_str(), S_IRUSR | S_IWUSR) < 0){
        if (errno != EEXIST){
            std::cerr << errno;
        }
    }
    std::ifstream file{pipe.c_str()};
    // ...
    /* Do check for data and read/deserialize if any data */
    // This is in some sort of loop that goes over the different
    // filestreams and checks to see if they have data to treat
}

非常感谢任何帮助...

编辑: 按照 Zoso 的回答,我尝试使用文件大小来确定文件是否已更改;但是尝试获取 fifo 命名管道的大小是不可能的: filesystem error: cannot get file size: Operation not supported [myFilePath]

【问题讨论】:

  • 非阻塞 I/O 对于 C++ 流来说并不简单。如果可以检索文件描述符,则可以使用 select/poll。这涉及一些黑客行为。或者,您可以直接使用 POSIX I/O,这将允许您 select/poll
  • 如果你能得到FD你可以使用ioctl(...FIONREAD).
  • @P.P +1 用于 poll 和 C,但不幸的是我将使用 boost 进行序列化并且使用文件描述符有点痛苦......

标签: c++ file nonblocking ostream


【解决方案1】:

我不确定这是否适用于您的特定用例,但您可以使用 filesystem API。一个简单的例子是

#include <iostream>
#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;
int main()
{
    while (true) {
        auto path = fs::current_path().append("test");
        std::cout <<"Press enter to know file size of "<<path.c_str() <<'\n';
        char c= getchar();
        try {
            std::cout<<"Size of "<<path.c_str()<<"is "<<fs::file_size(path)<<'\n';
        } catch(fs::filesystem_error& e) {
            std::cout << e.what() << '\n';
        }        
    }
}

当文件获取数据时,可以根据不断增加的size 对其进行跟踪,并且可以在使用该数据时跟踪要处理的数据。

【讨论】:

  • 我喜欢大码!我会尽快尝试的
猜你喜欢
  • 2019-09-27
  • 2012-11-30
  • 2021-11-22
  • 1970-01-01
  • 2016-08-05
  • 2011-02-13
  • 1970-01-01
  • 2014-07-18
  • 1970-01-01
相关资源
最近更新 更多