使用(希望是标准的)C++工具读取文件*

reading a FILE* with (hopefully standard) C++ tools?

本文关键字:工具 C++ 读取 文件 希望 标准 使用      更新时间:2023-10-16

我需要从我的程序中读取另一个程序的输出。为此,我可以使用 popen()。这样,我就可以得到一个可以在我的程序中解析的程序输出的 FILE*。如何从我的程序中读取和解析 popen() 返回值的内容?或者,在某个地方是否有更像 C++ 的 popen 版本?

您可以创建一个流缓冲区,执行道德等效popen(),也可以创建一个流缓冲区包装FILE*。获得流缓冲区后,您可以将其与std::istream一起使用,这似乎是您打算做的。从FILE*读取的简单(未经测试)流缓冲区如下所示:

struct FILEbuf
    : std::streambuf {
    FILEbuf(FILE* fp): fp_(fp) {}
    int underflow() {
        if (this->gptr() == this->egptr()) {
            int size = fread(this->buffer_, 1, s_size, this->fp_);
            if (0 < size) {
                this->setg(this->buffer_, this->buffer_, this->buffer_ + size);
            }
        }
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*gptr());
     }
     FILE* fp_;
     enum { s_size = 1024 };
     char  buffer_[s_size];
};

我认为我打错了一些东西,但大致这个想法确实有效:只需从FILE*读取到流缓冲区即可。或者,创建从生成的进程读取流。这需要几个特定于平台的调用来fork()exec..()pipe()close()dup2()(可能这里也忘记了一些东西),但也可以完成。

可以使用像上面这样的流缓冲区,例如,像这样:

int main()
{
    FILEbuf      sbuf(fopen("pstream.cpp", "r"));
    std::istream in(&sbuf);
    for (std::string line; std::getline(in, line); ) {
        std::cout << line << 'n';
    }
}

FILE*有一个C++包装器,称为stdio_filebuf(GNU实现)或stdiobuf。我认为这不是一个标准化的东西,但如果你谷歌搜索stdiobuf你会发现它在许多平台上都可用。下面是一个如何将其与从 popen 返回的 FILE* 指针一起使用的工作示例,使用 gcc 4.5.0 编译并在 Linux 机器上进行测试:

#include <ext/stdio_filebuf.h>
#include <stdio.h>
#include <fstream>
#include <string>
#include <iostream>
using namespace std;
int main() {
    FILE* f = popen("ls", "r");
    __gnu_cxx::stdio_filebuf<char> fdbuf(f, std::ios::in);
    std::ifstream in;
    in.std::ios::rdbuf(&fdbuf);
    string s;
    in >> s;
    cout << s;
    pclose(f);
    return 0;
}