打开临时C FILE *进行输入

时间:2015-03-02 10:26:16

标签: c file-io input

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

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

  • 此时数据在内存中
  • 在磁盘上打开一个临时文件(使用tmpnam或tmpfile)进行编写
  • fclose the file
  • 再次打开同一个文件进行阅读 - 保证存在
  • 使用setvbuf(缓冲区,大小)更改缓冲区
  • 做遗留的FILE * stuff
  • 关闭文件
  • 删除临时文件
  • 可以丢弃数据

在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);

2 个答案:

答案 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}}不提供更多保证。)

我认为最简单的可移植解决方案是将setvbuftmpfile数据用于该文件,fwrite开头(我不确定临时文件是否可以保证是可以搜索的,在我的Linux系统上,看起来它们是,并且我希望它们在其他地方),并将fseek指针传递给该函数。这仍然需要在内存中复制,但我想通常不会将数据写入磁盘(不幸的是,POSIX隐含地要求存在真实文件)。关闭后,FILE获取的文件将被删除。