C++内存流到C文件流

C++ memory stream to C file stream

给定一个 C++ std::istream 输入内存流,是否可以通过任何方式直接将该流中的数据写入 C 文件流 (FILE*) 而无需先将数据写入磁盘?

我问的原因是我有一个采用 FILE* 的 C 接口,为此我想透明地支持压缩或未压缩的输入文件。

想法是编写一个包装函数来获取输入文件,然后使用 boost::iostreams 创建一个过滤流,在必要时进行解压缩,然后以某种方式将解压缩的数据转发到 C API.

直接解压一个压缩文件,将解压后的数据写入磁盘,然后fopen临时文件。不过,我想避免创建临时文件。

另一种选择是将内存中的所有数据解压,然后使用fmemopen得到解压数据的FILE*。这意味着我可能不得不分配大量数据,但我更愿意看到一个缓冲解决方案。这有可能吗?

如果您使用的是 GNU 系统(Linux、Glibc),您可以使用 fopencookie 创建一个 FILE *解码操作的包装器:

FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs);

[...]

The fopencookie() function serves a purpose similar to fopen(3): it opens a new stream and returns a pointer to a FILE object that is used to operate on that stream.

The cookie argument is a pointer to the caller's cookie structure that is to be associated with the new stream. This pointer is supplied as the first argument when the standard I/O library invokes any of the hook functions described below.

The mode argument serves the same purpose as for fopen(3). The following modes are supported: r, w, a, r+, w+, and a+. See fopen(3) for details.

The io_funcs argument is a structure that contains four fields pointing to the programmer-defined hook functions that are used to implement this stream. The structure is defined as follows

typedef struct {
    cookie_read_function_t  *read;
    cookie_write_function_t *write;
    cookie_seek_function_t  *seek;
    cookie_close_function_t *close;
} cookie_io_functions_t;

[...]

(我不想将 整个 联机帮助页复制到我的答案中)。

基本上你可以这样做:

ssize_t my_read(void *cookie, char *buf, size_t size) {
    std::istream *the_stream = static_cast<std::istream*>(cookie);
    // insert magic
    return bytes_read;
}

cookie_io_functions_t my_functions = {
    my_read,
    NULL,
    NULL,
    NULL,
};

...

FILE *wrapped = fopencookie(static_cast<void *>&stream, "rb", my_functions);

在 BSD/OSX 上,您会同样幸运,因为它带有 funopen,只是 API 略有不同,可以实现完全相同的效果。

如果你想支持 Windows,那么 poor you