打开一个临时 C 文件* 用于输入

open a temporary C FILE* for input

我有一个遗留函数接受库中的 FILE* 指针。我要解析的内容实际上是在内存中,而不是在磁盘上。

所以我想出了以下步骤来解决这个问题:

在 windows 上,它看起来像这样:

int bufferSize;
char buffer[bufferSize];

// set up the buffer here

// temporary file name
char tempName [L_tmpnam_s];
tmpnam_s(tempName, L_tmpnam_s);

// open/close/reopen
fopen_s(&fp, tempName,"wb");
fclose(fp);
freopen_s(&fp, tempName,"rb", fp);

// replace the internal buffer
setvbuf(fp, buffer, _IONBF, bufferSize);
fp->_ptr = buffer;
fp->_cnt = bufferSize;

// do the FILE* reading here

// close and remove tmp file
fclose(fp);
remove(tempName);

可行,但相当麻烦。除了这种方法的落后之外,主要问题是:

我想让东西保持便携,所以使用 Windows 内存映射函数或 boost 的工具不是一个选择。问题主要在于,虽然可以将 FILE* 转换为 std::fstream,但反过来似乎是不可能的,或者至少在 C++99 上不受支持。

欢迎所有建议!

更新 1

按照 Speed8ump 的建议使用 pipe/fdopen/setvbuf 并进行一些调整似乎可行。它不再在磁盘上创建文件,也不会消耗额外的内存。更近了一步,只是出于某种原因,setvbuf 没有按预期工作。手动修复是可以的,当然不能移植。

// create a pipe for reading, do not allocate memory
int pipefd[2];
_pipe(pipefd, 0, _O_RDONLY | _O_BINARY);

// open the read pipe for binary reading as a file
fp = _fdopen(pipefd[0], "rb");

// try to switch the buffer ptr and size to our buffer, (no buffering)
setvbuf(fp, buffer, _IONBF, bufferSize);

// for some reason, setvbuf does not set the correct ptr/sizes      
fp->_ptr = buffer;
fp->_charbuf = fp->_bufsiz = fp->_cnt = bufferSize;

更新 2

哇。因此,除非我深入研究特定于 MS 的实现 CreateNamedPipe / CreateFileMapping,否则 POSIX 可移植性会花费我们整个 memcopy(任何大小!),无论是文件还是管道。希望编译器明白这只是临时的并对其进行优化。希望。

不过,我们消除了愚蠢的设备编写中间体。耶!

int pipefd[2];
pipe(pipefd, bufferSize, _O_BINARY);   // setting internal buffer size

FILE* in  = fdopen(pipefd[0], "rb");    
FILE* out = fdopen(pipefd[1], "wb");   

// the actual copy
fwrite(buffer, 1, bufferSize, out);  
fclose(out);

// fread(in), fseek(in), etc.. 

fclose(in);

您可以尝试使用管道和 fdopen,它似乎是可移植的,在内存中,并且您仍然可以执行您正在使用的 setvbuf 技巧。

您的 setvbuf hack 是个好主意,但不可移植。 C11 (n1570):

7.21.5.6 The setvbuf function

Synopsis

#include <stdio.h>
int setvbuf(FILE * restrict stream,
            char * restrict buf,
            int mode, size_t size);

Description

[...] If buf is not a null pointer, the array it points to may be used instead of a buffer allocated by the setvbuf function [...] and the argument size specifies the size of the array; otherwise, size may determine the size of a buffer allocated by the setvbuf function. The contents of the array at any time are indeterminate.

既不能保证提供的缓冲区会被使用,也不能保证在 setvbuf 调用之后直到文件关闭或再次调用 setvbuf 之前它包含的任何内容( POSIX 不提供更多保证)。

我认为最简单的便携式解决方案是使用 tmpfilefwrite 将数据放入该文件,fseek 到开头(我不确定临时文件是否是保证是可搜索的,在我的 Linux 系统上,它们似乎是,我希望它们在其他地方),并将 FILE 指针传递给函数。这仍然需要在内存中复制,但我想通常不会将数据写入磁盘(POSIX,不幸的是,隐含地需要一个真实的文件存在)。 tmpfile获取的文件关闭后被删除