如何使用 emscripten 将文件从 C 保存到浏览器存储

Posted

技术标签:

【中文标题】如何使用 emscripten 将文件从 C 保存到浏览器存储【英文标题】:How to save files from C to browser storage with emscripten 【发布时间】:2019-02-10 14:09:18 【问题描述】:

我用来在浏览器中运行game 的game engine 运行lua,并且在我的游戏中我使用普通的fopen / write / fclose 保存文件。引擎C/C++代码通过emscripten编译成JS。什么是让这些文件写入最终存储在本地存储或浏览器缓存位置的其他一些好方法?我已经搜索了网络并查看了文档,但信息非常稀少,我还没有找到任何明确的答案来说明这应该如何工作。

游戏引擎的前任贡献者在 emscripten 构建中添加了一个 js 库,它将覆盖 fclose 以回调 javascript。但是这个 fclose 覆盖似乎不再被调用,它根本不包含在最终的 .js 文件中。

【问题讨论】:

localStorage 有 5-10MB 的限制。是你想要的吗? 嗯,我有什么选择?索引数据库? 【参考方案1】:

Emscripten 文件系统 API 涵盖了您使用 IndexedDB 的案例。

这里是Filesystem API overview。它有四种类型:

    MEMFS:一种易失的内存存储。这是默认的文件系统类型,在运行时挂载在/NODEFS:这使用的是node.js fs api,这不是你的情况。 IDBFS:这利用了IndexedDB,您可以将其用于离线存储。 WORKERFS:这是为了在工作人员内部使用。

您可以将IDBFS 与 Emscripten 自己的 FS API 一起使用(虽然这是 JavaScript 端 API)。您需要先安装它才能使用它。您可以使用FS.mkdir,FS.mount, and FS.syncfs 来实现它。下面是一个 C 语言的粗略例子:

#include <emscripten.h>

int main() 
    // EM_ASM is a macro to call in-line JavaScript code.
    EM_ASM(
        // Make a directory other than '/'
        FS.mkdir('/offline');
        // Then mount with IDBFS type
        FS.mount(IDBFS, , '/offline');

        // Then sync
        FS.syncfs(true, function (err) 
            // Error
        );
    );

    // Use fopen / write / fclose in C here.
    int off_file = fopen("/offline/any_file");
    ...

    // Don't forget to sync to make sure you store it to IndexedDB
    EM_ASM(
        FS.syncfs(function (err) 
            // Error
        );
    );

Here is a more detailed example 来自 Emscripten 存储库。

【讨论】:

所以 EM_ASM 宏中的 javascript 在整个构建、llvm 和所有内容中都保持不变?游戏引擎有一个cmake构建系统,最后一个命令只是整个engine.so文件上的emcc,所以只是担心EM_ASM可能会在途中丢失。如果不是,这看起来真的很好 - 我可以用来同步的本机代码中已经有一个 fclose 钩子。 我可以从 javascript 端运行这些东西吗?挂载一个我知道游戏会写入内容的目录,同步,然后运行 ​​main,等待内容保存到游戏中,然后再次调用同步? 至少不用担心EM_ASM会丢失。因为您不仅要调用emcc,而且还必须在 Emscripten 环境中构建整个项目。也就是说,你必须使用emconfigure cmake . 命令而不是cmake .。 Take a look at Emscripten build process docs。如果你忽略 emconfigureemmake,你会遇到麻烦,因为 WebAssembly 是一个非常不同的环境。例如,它目前只有 32 位。 您可以在 JavaScript 中调用它们,但是 JS 代码必须是带有 --pre-js--post-js 构建选项的 emcc 命令的输入文件之一。如果您不喜欢 EM_ASM 成为您原始函数的一部分,那么 EM_JS option 可以将整个 C/C++ 函数转换为 JS,从而使其成为单独的 .c 文件。 引擎使用 cmake 和 emscripten 工具链文件,不幸的是我不知道它是如何工作的。这是一个大项目,我真的没有足够的能力开始做不同的事情。但是你的意思是我必须从--post-js 开始,因为这些文件系统功能没有暴露在外面?如果我使用EXPORT_RUNTIME_FUNCTIONS 或类似名称会怎样?我想我可以向Module--post-js 添加两个函数,比如Module["mountIDBFSdir"] = function(dir) ...Module["syncfs"] = function(callback) FS.syncfs(true, callback) 。你怎么看?

以上是关于如何使用 emscripten 将文件从 C 保存到浏览器存储的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React 中使用 Emscripten JavaScript 文件

如何使用 Emscripten 将对象从 Javascript 传递到 C++

如何使用库导入编译 C 文件到 webassembly 文件(Emscripten)

如何使用 Emscripten 将 Hello Word 从 Swift 编译为 JavaScript

如何设置基本的 C++/C 编译,然后为 emscripten 构建链接脚本

使用 emscripten 将字符串从 C++ 传递给 JS