【问题标题】:Make a file pointer read/write to an in-memory location使文件指针读/写到内存中的位置
【发布时间】:2011-02-27 20:49:29
【问题描述】:

我可以使用 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 类。

【问题讨论】:

  • 明确一点,当您使用fopen() 时,您创建的不是指向文件的指针,而是指向代表该文件的结构的指针。
  • @Jeff M 我知道。我只是使用了术语文件指针
  • 您是否真的想将一个六年前的问题标记为一个八年前没有公认答案的问题的重复?
  • 编辑们的时间难道没有更好的事情要做吗?

标签: c++ c


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    在 C++ 中(并且您添加了 C++ 标签),您可以编写一个接受任意输入/输出流的函数。由于std::stringstreamstd::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
      }
    }
    

    【讨论】:

    • 我添加了标签 C++,所以人们只看到标签 c++ 而不是 C 会看到我的问题。
    • @Leo Izen:C++ 的人会给出 C++ 的答案。
    【解决方案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::istreamstd::ostream 而不是低级C FILE* 对象,那么C++ 方便地提供std::istringstreamstd::ostringstream 用于读取/写入字符串。

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

    【讨论】:

    • 我知道,如果代码完全在内存中,设计代码效果最好,但是如果库已经存在并且需要 FILE * 呢?
    【解决方案4】:

    使用内存映射文件。这是特定于平台的,因此您需要找到有关在目标系统上创建内存映射文件的信息。我相信posix版本是mmap。无论如何,在谷歌上搜索“内存映射文件”应该会得到很多帮助。

    【讨论】:

    • 不,这是一种获取指向虚拟内存区域的指针的方法。他想要一个由内存支持的虚拟文件,而不是由文件支持的虚拟内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2012-04-29
    • 2015-01-31
    • 2012-02-15
    • 2012-09-15
    • 1970-01-01
    相关资源
    最近更新 更多