使文件指针读/写到内存中的位置

问题描述 投票:0回答:5

我可以使用 fopen() 将文件指针写入文件。但是我可以创建一个文件指针,以便调用 fputc 或 fprintf 等函数将写入内存中的指针吗? java 中的 ByteArrayOutputStream 就是一个例子。另外:我可以反向运行它吗,库需要一个文件指针来读取,所以我分配内存,并创建一个新的文件指针,该指针将从该内存位置读取,但当块的大小用完时返回 EOF ? (就像 Java 中的 ByteArrayInputStream)。有没有办法在 C 中做到这一点?例如:

FILE *p = new_memory_file_pointer();
fprintf(p, "Hello World!\n");
char *data = get_written_stuff(p);
printf("%s", data); //will print Hello World!

&& / ||

char s[] = "Hello World!\n";
FILE *p = new_memory_file_pointer_read(s, sizeof(s));
char *buffer = (char *)malloc( 1024*sizeof(char) );
fread((void *)buffer, 1, sizeof(s), p);
printf("%s", buffer); //prints Hello World!

编辑: 对于多年后阅读此问题的人,除了已接受的答案之外,您还应该查看

open_memstream(3)
,它的行为比
fmemopen
更像这些 Java 类。

c++ c
5个回答
27
投票

如果您的操作系统提供fmemopen, 也许它会满足你的目的。


4
投票

在 C++ 中(并且添加了 C++ 标签),您可以编写一个接受任意输入/输出流的函数。由于

std::stringstream
std::ofstream
是派生类,因此您可以将它们同等地传递到此函数中。一个例子:

#include <iostream> // for std::cout
#include <fstream> // for std::ofstream
#include <sstream> // for std::stringstream

void write_something(std::ostream& stream) {
  stream << "Hello World!" << std::endl;
}

int main() {
  write_something(std::cout); // write it to the screen
  {
    std::ofstream file("myfile.txt");
    write_something(file); // write it into myfile.txt
  }
  {
    std::stringstream stream;
    write_something(stream); // write it into a string
    std::cout << stream.str() << std::endl; // and how to get its content
  }
}

类似地,如果您想读取数据,请使用

std::istream
而不是
std::ostream

void read_into_buffer(std::istream& stream, char* buffer, int length) {
  stream.read(buffer, length);
}

int main() {
  char* buffer = new char[255];

  {
    std::ifstream file("myfile.txt");
    read_into_buffer(file, buffer, 10); // reads 10 bytes from the file
  }
  {
    std::string s("Some very long and useless message and ...");
    std::stringstream stream(s);
    read_into_buffer(stream, buffer, 10); // reads 10 bytes from the string
  }
}

3
投票

正如 Ise 恰当地指出的那样,POSIX 2008 中有一个用于此功能 fmemopen 的函数,并且 Linux 上支持该函数。使用 POSIX 2004,最接近的可能是使用临时文件:

// This is for illustration purposes only. You should add error checking to this.
char name[] = "/tmp/name-of-app-XXXXXX";
int temporary_descriptor = mkstemp(name);
unlink(temporary_descriptor);
FILE* file_pointer = fdopen(temporary_descriptor, "r+");
// use file_pointer ...

反过来更容易;也就是说,有一个写入内存的函数,然后使用它既写入内存又写入文件。您可以使用 mmap 以便一块内存最终由文件支持,并且写入该内存会将数据写入关联的文件。

如果您使用

std::istream
std::ostream
而不是低级 C FILE* 对象,那么 C++ 可以方便地提供
std::istringstream
std::ostringstream
来读取/写入字符串。

您会注意到,C 中几乎所有以“f”开头且对文件进行操作的函数,都有以“s”开头且对字符串进行操作的等效函数。也许更好的方法是设计一个不特定于文件或字符串的 I/O 接口,然后提供分别连接到文件和字符串的实现。然后根据该接口(而不是低级 C 和 C++ I/O)实现核心逻辑。这样做的好处还在于允许未来扩展,例如通过内置的压缩、复制等支持来支持网络文件。


0
投票

带有内存映射文件。这是特定于平台的,因此您需要查找有关在目标系统上创建内存映射文件的信息。我相信 posix 版本是

mmap
。无论如何,在谷歌上搜索“内存映射文件”应该会得到很多帮助。


0
投票

这是一个使用

fmemopen
的示例,适用于 Linux。显然 有人还为 Windows 编写了
fmemopen

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
  
  const char *fakeStdin = "The fake stdin input\n"
    "The end of the stream will be at the null ->";
  size_t streamBytes = strlen( fakeStdin );
  FILE *f = fmemopen( (void*)fakeStdin, streamBytes, "rb" );
  if( !f ) {
    puts( "Couldn't open FILE* to memory" );
    return 1;
  }

  char* buf = (char*)malloc( streamBytes + 1 );
  size_t readBytes = fread( buf, 1, streamBytes, f );
  printf( "Read %zu bytes from stream:\n", readBytes );
  
  puts( buf );
  
  free( buf );
  fclose( f );
  
  return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.