摘要:打包文件可以讓你指定你需要的文件,通過將他們打包進(jìn)虛擬文件系統(tǒng)。使用文件打包器打包文件,然后在創(chuàng)建和加載文件系統(tǒng)的時(shí)候生成文件系統(tǒng)調(diào)用。運(yùn)行時(shí),虛擬文件系統(tǒng)會(huì)映射同樣的要打包文件的目錄結(jié)構(gòu)。
翻譯:云荒杯傾
本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請(qǐng)查看專欄。
也可以去作者的博客閱讀文章。
這部分是關(guān)于如何在 Emscripten編譯的代碼中使用文件。包括以下部分:
文件系統(tǒng)概覽:總體介紹Emscripten支持的文件操作。
打包文件:怎樣使用emcc來打包編譯后的代碼所需要的文件。
同步虛擬XHR后臺(tái)文件系統(tǒng)使用:介紹如何使用XHR通過http完成二進(jìn)制數(shù)據(jù)的懶加載。
下面逐一講這三部分。
1、文件系統(tǒng)概述分兩部分,一部分介紹Emscripten的文件系統(tǒng)運(yùn)行環(huán)境,一部分介紹Emscripten 文件系統(tǒng)體系架構(gòu)。
Emscripten的文件系統(tǒng)運(yùn)行環(huán)境原生代碼和JS使用的文件存取模式有很大的不同。原生代碼使用libc和libcxx庫(kù)調(diào)用同步文件APIs,而JS中除了web worker都是只允許異步文件獲取的。另外,因?yàn)镴S處在瀏覽器沙箱環(huán)境中,它并不是直接對(duì)主機(jī)的文件系統(tǒng)進(jìn)行存取操作的。
Emscripten提供了一個(gè)虛擬的文件系統(tǒng)模擬本地文件系統(tǒng),所以原生代碼可以可以在很少或者不需要修改的情況下使用同步文件APIs。
打包文件可以讓你指定你需要的文件,通過emcc將他們打包進(jìn)虛擬文件系統(tǒng)。對(duì)于開發(fā)者來說,打包文件這一部分的知識(shí)是需要了解的。
Emscripten文件系統(tǒng)體系架構(gòu)下面列出了Emscripten文件系統(tǒng)的主要元素。大多數(shù)原生代碼都是調(diào)用libc和libcxx庫(kù)的同步文件API的,接下來他們將依次調(diào)用底層的文件系統(tǒng)API,默認(rèn)使用MEMFS虛擬文件系統(tǒng)。
當(dāng)運(yùn)行時(shí)初始化時(shí),MEMFS掛載在根目錄下。而添加到MEMFS的文件是在編譯期間通過emcc打包進(jìn)來的。當(dāng)HTML頁(yè)面加載完成后,JS使用同步XHR異步加載(load)這些文件。只有當(dāng)異步加載完成,文件在虛擬文件系統(tǒng)可用的時(shí)候,才能執(zhí)行編譯代碼。
因?yàn)镸EMFS實(shí)際上存在內(nèi)存中,頁(yè)面reload完成的時(shí)候,所有寫入的數(shù)據(jù)都會(huì)丟失掉。如果想持久化這些寫入的東西,請(qǐng)?jiān)跒g覽器中掛載IDBFS文件系統(tǒng),或者Nodejs中掛載NODEFS。NODEFS可以訪問本地文件系統(tǒng)。你可以通過自己寫JS的方式掛載新的文件系統(tǒng),然后執(zhí)行這些文件系統(tǒng)中的適合你的文件操作。
如果你需要從網(wǎng)絡(luò)取其他文件到文件系統(tǒng),請(qǐng)使用 Emscripten Asynchronous File System API中的emscripten_wget()和其他方法。這些方法是同步的,應(yīng)用程序必須等待回調(diào)完成完成。
2、打包文件有預(yù)加載(preloading)和嵌入(embedding)兩種可交換的打包方式。嵌入式是將具體文件與編譯生生的JS文件混到一起,放同一個(gè)文件。而預(yù)加載可以將文件多帶帶打包到一個(gè)文件中。嵌入的方式比預(yù)加載低效,使用情況是要打包的文件數(shù)量和文件大小都比較小。
emcc使用文件打包器打包文件,然后在創(chuàng)建和加載文件系統(tǒng)的時(shí)候生成文件系統(tǒng)調(diào)用。雖然emcc是推薦的打包工具,但是你也可以直接手動(dòng)使用文件打包器進(jìn)行自行打包。
用emcc打包打包文件最簡(jiǎn)單的方式是在編譯的時(shí)候通過emcc打包。preload和embed代表你選擇的打包方式。
下面是一個(gè)示例打包命令:
./emcc file.cpp -o file.html --preload-file asset_dir
這個(gè)命令會(huì)生成file.html,file.js,file.data。這個(gè).data文件包含了asset_dir目錄下的所有文件,通過file.js來加載它。
下面這個(gè)命令展示了嵌入方式打包。此時(shí),emcc生成file.html,file.js。 asset_dir/ 目錄中的內(nèi)容都直接被打包進(jìn)file.js了。
./emcc file.cpp -o file.html --embed-file asset_dir
默認(rèn)下,要打包的文件應(yīng)該嵌套在或就在編譯命令此時(shí)cd的目錄下。運(yùn)行時(shí),虛擬文件系統(tǒng)會(huì)映射同樣的要打包文件的目錄結(jié)構(gòu)。虛擬文件系統(tǒng)的根目錄對(duì)應(yīng)著編譯命令此時(shí)cd的目錄。
舉例,有dir1/dir2/dir3/asset_dir/的一個(gè)目錄結(jié)構(gòu),dir2是要編譯的項(xiàng)目,我們要打包asset_dir的話,就用相對(duì)路徑dir3/asset_dir/。emcc的命令窗口在dir2目錄打開。
./emcc file.cpp -o file.html --preload-file dir3/asset_dir
打包編譯完成后,在虛擬文件系統(tǒng)中也是通過dir3/asset_dir這樣的路徑來找asset_dir文件夾。相似的,如果我們是在dir2下打包了一個(gè)文件的話,項(xiàng)目運(yùn)行時(shí)就應(yīng)該在虛擬文件系統(tǒng)的根目錄下來找dir2目錄。
打包時(shí),還有一個(gè)@符號(hào)的用法,它是指將任何本地文件系統(tǒng)中任何目錄下的文件映射到編譯后的虛擬文件系統(tǒng)中的某路徑。
用文件打包器打包除了通過emcc命令編譯時(shí)打包,你也可以手動(dòng)運(yùn)行文件打包器file_packager.py來打包。
打包器會(huì)成.data文化和.js文件。.js文件包含使用.data文件的代碼。
NOTE: * 使用文件打包器打包使你不用非要在編譯的時(shí)候(用emccd來編譯)打包。 * 使用文件打包器可對(duì)多個(gè)數(shù)據(jù)文件逐一打包,然后輸出很多.js文件。改變.data文件的位置
默認(rèn)下,.data文件和.js文件通過相同URL加載。有時(shí)候讓你的數(shù)據(jù)文件和其他類型文件分開,處在不同位置是有用的。
使用 Module.filePackagePrefixURL完成存儲(chǔ)前的路徑修改。這個(gè)屬性要在加載它的