C++文件不写入磁盘

8
我正在使用一个库,它有很多写入FILE的函数,但没有一个方便地将相同数据转储到内存中的对象。是否有任何方法创建一个FILE对象(或覆盖它),以将数据存储在内存中而不是写入磁盘 - 我想避免打开/写入/读取文件的性能损失。

更新:根据Rob的建议,尝试stringstream:

ss.put(c);

std::string myval = ss.str();

printf("Value: %s\n after writing: %i length %lu\n",myval.c_str(),c, myval.length());

但是,现在我试图从stringstream中获取数据(二进制)时遇到了困难 - 我该如何获取我一直添加的二进制数据?


1
仅为完整起见,我提到std::stringstreamstringstream无法解决OP的问题,因为他被绑定在FILE上。如果他可以修改他的库,他就可以使用stringstream - Robᵩ
@Rob - 我的目标是避免修改库的源代码(以避免升级时出现冲突等问题),但我确实有这个选项。我认为我可能会选择这条路,因为其他解决方案看起来比我的C语言技能更低级。基本上,我需要替换或增强一个当前正在使用fputc的函数 - 我将使用stringstream中的put代替,对吧? - jnpdx
不要害怕使用fmemopenopen_memstream。它们看起来是您的完美解决方案。但是,如果您确实想使用stringstream,请参考我的答案。 - Robᵩ
这两个函数在我的iOS设备上都不可用,所以我只能使用mmap等其他方法,但这也是我目前不太熟悉的事情! - jnpdx
你的问题非常适合面试! - user349026
6个回答

11
除了已经提到的GNU的fmemopen(),在POSIX中被称为open_memstream之外,还可以通过结合mmap()(使用MAP_ANONYMOUS)或其他返回内存块文件描述符的特定于操作系统的函数以及fdopen()来获得类似的解决方案。

编辑:这是错误的,mmap不会创建文件描述符。


很棒的答案。我的C语言技能有限,让我对深入其中感到担忧--请看我在原始帖子上对Rob的评论。也许只需对原始库进行小修改就可以解决问题。 - jnpdx
你是如何从mmap中获取一个文件描述符,以便可以与fdopen一起使用的?我正在尝试获取一个指向内存中没有支持文件的mmap位置的FILE指针。 - featherless
@featherless 你说得对,mmap 不会创建文件描述符。我在写那段话时想到的是 shm_open,但是 shm_open 的文件描述符不能在 fdopen 中使用。感谢你指出这个错误! - Cubbi

5
GNU libc提供了fmemopen函数,它可以返回一个指向内存的FILE *指针。在Linux系统上使用man fmemopen查看详细信息。
我猜测(但不确定)fmemopen是一个包装器,它会调用@Cubbi提到的mmap/fdopen方法。

2

1

如果您有修改库的选项,可以使用C++流而不是C FILE流。

如果您的旧库函数如下所示:

void SomeFun(int this, int that, FILE* logger) {
  ... other code ...
  fprintf(logger, "%d, %d\n", this, that);
  fputs("Warning Message!", logger);
  char c = '\n';
  fputc(c, logger);
}

你可以用以下代码替换它:

void SomeFun(int this, int that, std::ostream& logger) {
  ... other code ...
  logger << this << ", " << that << "\n";
  // or: logger << boost::format("%d %d\n") %this %that;
  logger << "Warning Message!";
  char c = '\n';
  logger.put(c);
  // or: logger << c;
}

然后,在您的非库代码中,执行以下操作:

#include <sstream>    
std::stringstream logStream;
SomeFun(42, 56, logStream);
DisplayCStringOnGui(logStream.str().c_str());

我已经让它工作了,至少到了一个基本点。现在遇到的问题是如何获取数据——这是二进制数据。目前,我有:ss.put(c); std::string myval = ss.str(); printf("Value: %s\n after writing: %i length %lu\n",myval.c_str(),c, myval.length());length() 调用给出了一个准确增加的值,但我卡在了尝试获取数据上——c_str 给出了一个长度为 4 的 const char*,缺少大部分二进制数据。 - jnpdx
1
如果库返回的数据是二进制的(也就是说,可能在其中嵌入了 '\0' 字符),那么您将无法使用 printf("%s", ...) 访问它。您只是想显示这些数据吗?还是需要将其传递给另一个函数?您可以像这样逐字节访问数据:myval[i]。或者您可以像这样传递指向数据的指针:MyFunc(myval.data(), myval.length()) - Robᵩ

0
考虑挂载tmpfs并让应用程序向其写入。当然,这仅适用于*nix系统。

0

https://github.com/Snaipe/fmem 看起来是一个可移植的 C 语言 fmemopen。它提供了一个 FILE,您可以将数据写入其中,完成后会返回一个指向数据所在内存的 void*


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接