跨平台的C/C++程序常使用fopen()、fread()、fwrite()等Libc/LibCXX提供的同步文件访问函数。通常在文件系统方面,JavaScript程序与C/C++本地程序有巨大的差异,主要体现在:
Emscripten提供了一套虚拟文件系统,以兼容Libc/LibCXX提供的同步文件访问函数。
在最底层,Emscripten提供了3种文件系统,分别为MEMFS(内存文件系统)、NODEFS、IDBFS。它们各自的特点:
文件导入MEMFS系统之前,需要先将其打包。文件打包有两种方式:
文件数据被转为JavaScript代码;
(对于embed模式,其需要将数据文件化编码,所产生的文件包体积大于preload模式下产生的文件包体积,因此除非需要打包的文件总数据量非常小,否则尽可能使用preload模式)
除了生成.js文件外,还会额外生成同名的.data文件。其中,.data文件包含所有文件的二进制数据,.js文件包含.data文件包下载、装载操作的胶水代码。
int main()
{
FILE* fp = fopen("hello.txt","rt");
if(fp)
{
while(!feof(fp))
{
char c = fgetc(fp);
if(c!=EOF)
{
putchar(c);
}
}
fclose(fp);
}
return 0;
}
emcc pack.c -o pack.js --preload-file hello.txt
--preload-file参数不仅可以打包单个文件,还可以打包整个目录。
emcc pack.c -o pack.js --preload-file dat_dir
生成的打包文件pack.data包括dat_dir内的所有内存
步骤一:
python /home/hyde/emsdk/upstream/emscripten/tools/file_packager.py fp.data --preload file --js-output=fp.js
将file目录内的文件打包成fp.data和fp.js文件。
步骤二:
使用外挂文件包时,主程序编译必须增加 -s FORCE_FILESYSTEM=1参数以强制启用文件系统。
emcc test.c -o test.js -s FORCE_FILESYSTEM=1
步骤三:
在网页中,必须先引入外挂文件包.js,再引入主程序.js
<script src="fp.js"></script>
<script src="test.js"></script>
虽然下载文件包是异步的,但是Emscripten可以确保运行时准备就绪时,文件系统初始化完成,因此在Module.onRuntimeInitialized()回调函数中使用文件系统是安全的。
void setup_nodefs(){
EM_ASM(
FS.mkdir('/data');
FS.mount(NODEFS,{root:'.'},'/data');
);
}
int main()
{
setup_nodefs();
FILE* fp = fopen("/data/nodefs_data.txt","r+t");
if(fp == NULL)
{
fp = fopen("/data/nodefs_data.txt","w+t");
}
int count =0 ;
if(fp)
{
fscanf(fp,"%d",&count);
count++;
fseek(fp,0,SEEK_SET);
...
}
else{
printf("fopen failed\n");
}
return 0;
}
EMSCRIPTEN_KEEPALIVE
void test()
{
FILE* fp = fopen("/data/nodefs.txt","r+t");
...
}
int main(){
EM_ASM(
FS.mkdir('/data');
FS.mount(IDBFS,{},'/DATA');
FS.syncfs(true,function(err){
assert(!err);
ccall('test','v');
});
);
return 0;
}