我有一个遗留函数接受库中的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内存映射功能或增强功能不是一种选择。问题主要在于,虽然可以将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);
答案 0 :(得分:2)
您可能尝试使用管道和fdopen,它似乎是可移植的,在内存中,您可能仍然可以执行您正在使用的setvbuf技巧。
答案 1 :(得分:1)
你的setvbuf
黑客是一个好主意,但不是便携式的。 C11(n1570):
7.21.5.6
setvbuf
函数概要
#include <stdio.h> int setvbuf(FILE * restrict stream, char * restrict buf, int mode, size_t size);
描述
[...]如果
buf
不是空指针,则可以使用它指向的数组而不是setvbuf
函数[...]和参数{分配的缓冲区}。 {1}}指定数组的大小;否则,size
可以确定size
函数分配的缓冲区的大小。任何时候数组的内容都是不确定的。
在setvbuf
调用之后的任何时刻都没有保证提供缓冲区,也不保证它包含的内容,直到文件关闭或再次调用setvbuf
为止{{{ 3}}不提供更多保证。)
我认为最简单的可移植解决方案是将setvbuf
,tmpfile
数据用于该文件,fwrite
开头(我不确定临时文件是否可以保证是可以搜索的,在我的Linux系统上,看起来它们是,并且我希望它们在其他地方),并将fseek
指针传递给该函数。这仍然需要在内存中复制,但我想通常不会将数据写入磁盘(不幸的是,POSIX隐含地要求存在真实文件)。关闭后,FILE
获取的文件将被删除。