檔案系統 API

Emscripten 中的檔案操作由 FS 函式庫提供。它在內部用於 Emscripten 的所有 libclibcxx 檔案 I/O。

注意

API 的靈感來自 Linux/POSIX 檔案系統 API,兩者都呈現非常相似的介面。

底層行為也很相似,除非原生環境和瀏覽器環境之間的差異使其不合理。例如,使用者和群組權限已定義,但在 FS.open() 中會被忽略。

Emscripten 主要編譯使用同步檔案 I/O 的程式碼,因此大多數 FS 成員函式都提供同步介面 (錯誤透過引發 FS.ErrnoError 類型的例外回報)。

Emscripten 中的檔案資料會依掛載的檔案系統進行分割。提供多種檔案系統。依預設,MEMFS 的執行個體會掛載到 /。除了其他特殊裝置和串流 (例如 /dev/null/dev/random/dev/stdin/proc/self/fd) 之外,還會自動建立子目錄 /home/web_user/tmp;如需完整詳細資料,請參閱 FS 函式庫中的 FS.staticInit()NODEFSIDBFS 的執行個體可以掛載到其他目錄,如果您的應用程式需要 保存資料

test/test_core.py 中的自動測試 (搜尋 test_files) 包含許多如何使用此 API 的範例。教學課程 也示範如何預先載入檔案,以便可以從編譯的 C/C++ 中讀取檔案。

檔案系統概觀 中提供了 Emscripten 移植程式碼中檔案系統運作方式的高階概觀。

新的檔案系統:WasmFS

注意

目前狀態:開發中

WasmFS 是 Emscripten 的高效能、完全多執行緒、以 WebAssembly 為基礎的檔案系統層,它將取代現有的 JavaScript 版本。

JavaScript 為基礎的檔案系統最初是在支援 pthreads 之前撰寫的,當時在 JS 中撰寫程式碼更為理想。因此,它在 pthreads 建置中會有額外負擔,因為我們必須代理到所有檔案系統操作都在其中完成的主執行緒。相反地,WasmFS 會編譯成 Wasm,並具有完整的多執行緒支援。它的目標也是更模組化和可擴充。

設計文件連結

GitHub 追蹤問題

您可能會注意到與原始 JS 檔案系統的差異包括

  • 原始 JS FS 預設會包含許多 JS 程式碼,而 WasmFS 則不會。因此,如果您自己撰寫 JS,例如 FS.mkdir(),則 JS FS 會已新增該 API 支援,而且一切都會正常運作。使用 WasmFS 時,您必須選擇加入以包含完整的 JS API,以避免膨脹所有建置。若要這麼做,請使用 -sFORCE_FILESYSTEM,這會強制從 JS 支援完整的檔案系統 API。

  • WasmFS 在內部需要 malloc,因此您無法使用 -sWASMFS -sMALLOC=none 進行建置。如果您想要最小的 malloc,請使用 -sMALLOC=emmalloc。(請注意,如果您的程式碼實際上並未使用檔案,則最佳化工具可能會移除 WasmFS 和 malloc。)

包含檔案系統支援

Emscripten 會自動決定是否包含檔案系統支援。許多程式不需要檔案,而且檔案系統支援的大小不小,因此 Emscripten 會避免在沒有理由的情況下包含檔案系統支援。這表示如果您的 C/C++ 程式碼未存取檔案,則輸出中不會包含 FS 物件和其他檔案系統 API。另一方面,如果您的 C/C++ 程式碼確實使用檔案,則會自動包含檔案系統支援。因此,通常情況會「正常運作」,而您根本不需要考慮這個問題。

但是,如果您的 C/C++ 程式碼未使用檔案,但您想從 JavaScript 使用它們,則可以使用 -sFORCE_FILESYSTEM 進行建置,這會讓編譯器包含檔案系統支援,即使它看不到正在使用它。

另一方面,如果您想要包含任何檔案系統支援程式碼 (甚至可能因為 musl 和 libc++ 的結構而因 printf 或 iostreams 而包含),則可以使用 -sFILESYSTEM=0 進行建置。在這種情況下,如果需要,會包含非常簡單的 stdout 支援,足以讓 printf 等功能正常運作,但不會新增任何檔案系統程式碼,這可以節省大量的程式碼大小。

永久性資料

使用 Emscripten 編譯的應用程式通常會預期同步 I/O,因此 Emscripten 本身提供具有完全同步介面的檔案系統。

但是,由於 JavaScript 的事件導向特性,大多數永久性儲存選項只提供非同步介面。Emscripten 提供 多個檔案系統,這些檔案系統可以使用 FS.mount() 進行掛載,以協助處理依執行內容而定的持久性。

檔案系統

注意

預設情況下,僅包含 MEMFS 檔案系統。所有其他檔案系統都必須明確啟用,使用 -lnodefs.js (NODEFS)、-lidbfs.js (IDBFS)、-lworkerfs.js (WORKERFS) 或 -lproxyfs.js (PROXYFS)。

MEMFS

這是初始化執行環境時掛載在 / 的預設檔案系統。所有檔案都嚴格存在於記憶體中,並且任何寫入其中的資料都會在頁面重新載入時遺失。

NODEFS

注意

此檔案系統僅適用於在 node.js 內執行時。

此檔案系統允許在 node 中的程式將主機檔案系統上的目錄(透過掛載操作)對應到 Emscripten 虛擬檔案系統中的目錄。它使用 node 的同步 FS API 來立即將任何寫入 Emscripten 檔案系統的資料持久化到您的本機磁碟。

請參閱 此測試 以取得範例。

NODERAWFS

注意

此檔案系統僅適用於在 node.js 內執行時。

這是一個特殊的後端,它會將所有正常的檔案系統存取替換為直接的 Node.js 操作,而無需執行 FS.mount()。初始工作目錄將與 process.cwd() 相同,而不是 VFS 根目錄。由於此模式直接使用 Node.js 來存取您作業系統上的真實本機檔案系統,因此程式碼不一定在不同的作業系統之間可攜 — 它將像 Node.js 程式一樣可攜,這意味著底層作業系統處理權限和錯誤等方式的差異可能會很明顯。目前主要在 Linux 上進行測試。

請參閱 關於 NODEFS 的章節,您可以在其中看到掛載操作 — 這在 NODERAWFS 中不需要。

IDBFS

注意

此檔案系統僅適用於在瀏覽器內執行程式碼時。

IDBFS 檔案系統實作了 FS.syncfs() 介面,在呼叫時會將任何操作持久化到 IndexedDB 執行個體。

提供此功能是為了克服瀏覽器不提供用於持久儲存的同步 API 的限制,因此(預設情況下)所有寫入都僅暫時存在於記憶體中。

如果在掛載 IDBFS 時傳遞了掛載選項 autoPersist: true,則每當對 IDBFS 目錄樹進行任何變更時,都會自動將其持久化到 IndexedDB 後端。這讓使用者可以避免需要手動呼叫 FS.syncfs 來將變更持久化到已掛載的 IDBFS 目錄樹。

WORKERFS

注意

此檔案系統僅適用於在 worker 內執行程式碼時。

此檔案系統提供對 worker 內的 FileBlob 物件的唯讀存取,而無需將整個資料複製到記憶體中,並且可能用於大型檔案。

PROXYFS

這允許模組掛載另一個模組的檔案系統。當個別模組需要共享檔案系統而無需手動同步檔案內容時,這非常有用。例如

// Module 2 can use the path "/fs1" to access and modify Module 1's filesystem
module2.FS.mkdir("/fs1");
module2.FS.mount(module2.PROXYFS, {
    root: "/",
    fs: module1.FS
}, "/fs1");

裝置

Emscripten 支援註冊由裝置 ID 和一組裝置特定串流回呼組成的任意裝置驅動程式。一旦使用 FS.registerDevice() 註冊了驅動程式,就可以建立裝置節點來引用它(使用 FS.mkdev())。

裝置節點充當裝置和檔案系統之間的介面。任何引用新節點的串流都將繼承為該裝置註冊的串流回呼,使所有高階 FS 操作都與該裝置透明地互動。

注意

每個裝置都不同且獨一無二。雖然通常支援 openclosereadwrite 等常見檔案操作(並由檔案串流繼承,以提供用於呼叫等效 libc 函數的抽象層),但每個裝置都應根據其獨特的特性實作所需的任何回呼。

FS.makedev(ma, mi)

將主號和次號轉換為單一唯一整數。這用作表示裝置的 ID。

引數
  • ma – 主號。

  • mi – 次號。

FS.registerDevice(dev, ops)

使用一組回呼註冊指定的裝置驅動程式。

引數
  • dev – 使用 makedev() 建立的特定裝置驅動程式 ID。

  • ops (object) – 裝置所需的回呼集。如需範例,請參閱 NODEFS 預設回呼

設定標準 I/O 裝置

Emscripten 標準 I/O 的工作原理是透過虛擬的 /dev/stdin/dev/stdout/dev/stderr 裝置。您可以透過呼叫 FS.init() 來使用自己的 I/O 函數設定它們。

預設情況下

  • stdin 將從命令列引擎中的終端機讀取,並在瀏覽器中使用 window.prompt()(在這兩種情況下,都具有行緩衝)。

  • stdout 將使用 print 函數(如果已定義此函數),在命令列引擎中列印到終端機,並在具有主控台的瀏覽器中列印到瀏覽器主控台(同樣,具有行緩衝)。

  • stderr 將使用與 stdout 相同的輸出函數。

注意

所有設定都應在執行主要的 run() 方法之前完成,通常透過實作 Module.preRun。如需更多資訊,請參閱 與程式碼互動

FS.init(input, output, error)

stdinstdoutstderr 設定標準 I/O 裝置。

裝置是使用以下(可選)回呼設定的。如果任何回呼擲回例外,則會捕獲並處理,如同裝置發生故障一樣。

引數
  • input – 輸入回呼。每當程式嘗試從 stdin 讀取時,都會在沒有參數的情況下呼叫此回呼。當資料可用時,它應傳回 ASCII 字元碼,否則應傳回 null

  • output – 輸出回呼。每當程式寫入 stdout 時,都會使用 ASCII 字元碼呼叫此回呼。也可以使用 null 呼叫它來清空輸出。

  • error – 錯誤回呼。這與 output 類似,只是在資料寫入 stderr 時會呼叫它。

檔案系統 API

注意

從 libc 衍生的函數(例如 FS.readdir())使用全小寫名稱,而新增的函數(例如 FS.readFile())則使用駝峰式大小寫名稱。

FS.mount(type, opts, mountpoint)

type 指定的 FS 物件掛載到 mountpoint 指定的目錄。 opts 物件會因每個檔案系統類型而異。

引數
  • type檔案系統類型MEMFSNODEFSIDBFSWORKERFS

  • opts (物件) –

    基礎檔案系統使用的通用設定物件。

    NODEFS 使用 root 參數將 Emscripten 目錄對應到實體目錄。例如,將目前資料夾掛載為 NODEFS 實例

    FS.mkdir('/working');
    FS.mount(NODEFS, { root: '.' }, '/working');
    

    WORKERFS 接受 filesblobs 參數,將提供的平面檔案清單對應到 mountpoint 目錄

    var blob = new Blob(['blob data']);
    FS.mkdir('/working');
    FS.mount(WORKERFS, {
      blobs: [{ name: 'blob.txt', data: blob }],
      files: files, // Array of File objects or FileList
    }, '/working');
    

    您也可以傳入由 tools/file_packager 使用 --separate-metadata 建立的檔案包。您必須以 JSON 物件形式提供中繼資料,並以 blob 形式提供資料

    // load metadata and blob using XMLHttpRequests, or IndexedDB, or from someplace else
    FS.mkdir('/working');
    FS.mount(WORKERFS, {
      packages: [{ metadata: meta, blob: blob }]
    }, '/working');
    

  • mountpoint (字串) – 檔案系統要掛載到的現有本機 Emscripten 目錄路徑。它可以是絕對路徑,也可以是相對於目前目錄的路徑。

FS.unmount(mountpoint)

卸載指定的 mountpoint

引數
  • mountpoint (字串) – 要卸載的目錄。

FS.syncfs(populate, callback)

負責以非同步方式迭代並同步所有已掛載的檔案系統。

注意

目前,只有 IDBFS 檔案系統實作了同步所需的介面。所有其他檔案系統都是完全同步的,不需要同步。

populate 旗標用於控制 Emscripten 內部資料與檔案系統的持久資料之間基礎同步的預期方向。

例如

function myAppStartup(callback) {
  FS.mkdir('/data');
  FS.mount(IDBFS, {}, '/data');

  FS.syncfs(true, function (err) {
  // handle callback
  });
}

function myAppShutdown(callback) {
  FS.syncfs(function (err) {
  // handle callback
  });
}

此功能的真實範例可在 test_idbfs_sync.c 中看到。

引數
  • populate (布林值) – true 表示使用檔案系統持久來源的資料初始化 Emscripten 的檔案系統資料,而 false 表示將 Emscripten 的檔案系統資料儲存到檔案系統的持久來源。

  • callback – 同步完成時呼叫的通知回呼函式。如果發生錯誤,會將其作為參數提供給此函式。

FS.mkdir(path, mode)

在檔案系統中建立新的目錄節點。例如

FS.mkdir('/data');

注意

基礎實作不支援使用者或群組權限。呼叫者一律被視為資料夾擁有者,且僅套用與擁有者相關的權限。

引數
FS.mkdev(path, mode, dev)

在檔案系統中建立新的裝置節點,以參照 dev 的已註冊裝置驅動程式(FS.registerDevice())。例如

var id = FS.makedev(64, 0);
FS.registerDevice(id, {});
FS.mkdev('/dummy', id);
引數
  • path (字串) – 新裝置節點的路徑名稱。

  • mode (整數) –

    新節點的檔案權限。預設設定(以八進位數字表示法)為 0777。

  • dev (整數) – 已註冊的裝置驅動程式。

newpath 建立符號連結節點,連結至 oldpath。例如

FS.writeFile('file', 'foobar');
FS.symlink('file', 'link');
引數
  • oldpath (字串) – 要連結的檔案路徑名稱。

  • newpath (字串) – 指向 oldpath 的新符號連結節點路徑。

FS.rename(oldpath, newpath)

oldpath 的節點重新命名為 newpath。例如

FS.writeFile('file', 'foobar');
FS.rename('file', 'newfile');
引數
  • oldpath (字串) – 舊路徑名稱。

  • newpath (字串) – 新路徑名稱

FS.rmdir(path)

移除位於 path 的空目錄。

範例

FS.mkdir('data');
FS.rmdir('data');
引數
  • path (字串) – 要移除的目錄路徑。

取消連結 path 的節點。

這會從檔案系統中移除名稱。如果該名稱是檔案的最後一個連結(且沒有任何程序開啟該檔案),則會刪除該檔案。

例如

FS.writeFile('/foobar.txt', 'Hello, world');
FS.unlink('/foobar.txt');
引數
  • path (字串) – 目標節點的路徑。

取得儲存在 path 符號連結中的字串值。例如

#include <stdio.h>
#include <emscripten.h>

int main() {
  MAIN_THREAD_EM_ASM(
  FS.writeFile('file', 'foobar');
  FS.symlink('file', 'link');
  console.log(FS.readlink('link'));
  );
  return 0;
}

輸出

file
引數
  • path (字串) – 目標檔案的路徑。

傳回

儲存在 path 符號連結中的字串值。

FS.stat(path)

取得包含 path 節點相關統計資料的 JavaScript 物件。例如

#include <stdio.h>
#include <emscripten.h>

int main() {
  MAIN_THREAD_EM_ASM(
  FS.writeFile('file', 'foobar');
  console.log(FS.stat('file'));
  );
  return 0;
}

輸出

{
  dev: 1,
  ino: 13,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  size: 6,
  atime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST),
  mtime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST),
  ctime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST),
  blksize: 4096,
  blocks: 1
}
引數
  • path (字串) – 目標檔案的路徑。

FS.lstat(path)

FS.stat() 相同。但是,如果 path 是符號連結,則傳回的統計資料將是連結本身的統計資料,而非其連結到的檔案統計資料。

引數
  • path (字串) – 目標檔案的路徑。

FS.chmod(path, mode)

path 的模式旗標變更為 mode

注意

基礎實作不支援使用者或群組權限。呼叫者一律被視為資料夾擁有者,且僅套用與擁有者相關的權限。

例如

FS.writeFile('forbidden', 'can\'t touch this');
FS.chmod('forbidden', 0000);
引數
FS.lchmod(path, mode)

FS.chmod() 相同。但是,如果 path 是符號連結,則模式會設定在連結本身,而非其連結到的檔案上。

引數
FS.fchmod(fd, mode)

FS.chmod() 相同。但是,原始檔案描述元會作為 fd 提供。

引數
FS.chown(path, uid, gid)

將指定檔案的所有權變更為給定的使用者或群組 ID。

注意

此呼叫的存在是為了為移植程式碼提供更「完整」的 API 對應。設定的值實際上會被忽略。

引數
  • path (字串) – 目標檔案的路徑。

  • uid (整數) – 將取得檔案所有權的使用者 ID。

  • gid (整數) – 將取得檔案所有權的群組 ID。

FS.lchown(path, uid, gid)

FS.chown() 相同。然而,如果 path 是一個符號連結,則屬性會設定在連結本身,而不是它所連結的檔案上。

注意

此呼叫的存在是為了為移植程式碼提供更「完整」的 API 對應。設定的值實際上會被忽略。

引數
  • path (字串) – 目標檔案的路徑。

  • uid (整數) – 將取得檔案所有權的使用者 ID。

  • gid (整數) – 將取得檔案所有權的群組 ID。

FS.fchown(fd, uid, gid)

FS.chown() 相同。然而,原始檔案描述符會以 fd 提供。

注意

此呼叫的存在是為了為移植程式碼提供更「完整」的 API 對應。設定的值實際上會被忽略。

引數
  • fd (整數) – 目標檔案的描述元。

  • uid (整數) – 將取得檔案所有權的使用者 ID。

  • gid (整數) – 將取得檔案所有權的群組 ID。

FS.truncate(path, len)

將檔案截斷為指定的長度。例如:

#include <stdio.h>
#include <emscripten.h>

int main() {
  MAIN_THREAD_EM_ASM(
  FS.writeFile('file', 'foobar');
  FS.truncate('file', 3);
  console.log(FS.readFile('file', { encoding: 'utf8' }));
  );
  return 0;
}

輸出

foo
引數
  • path (字串) – 要截斷的檔案路徑。

  • len (整數) – 檔案的截斷長度。

FS.ftruncate(fd, len)

fd 所識別的檔案截斷為指定的長度 (len)。

引數
  • fd (整數) – 要截斷的檔案的描述符。

  • len (整數) – 檔案的截斷長度。

FS.utime(path, atime, mtime)

變更位於 path 的檔案的時間戳記。傳遞給引數的時間是以自 1970 年 1 月 1 日 (午夜 UTC/GMT) 以來的毫秒為單位。

請注意,在目前的實作中,儲存的時間戳記是單一值,即 atimemtime 的最大值。

引數
  • path (字串) – 要更新的檔案路徑。

  • atime (整數) – 檔案存取時間 (毫秒)。

  • mtime (整數) – 檔案修改時間 (毫秒)。

FS.open(path, flags[, mode])

以指定的旗標開啟檔案。flags 可以是:

  • r — 開啟檔案以供讀取。

  • r+ — 開啟檔案以供讀取和寫入。

  • w — 開啟檔案以供寫入。

  • wx — 與 w 類似,但如果路徑存在則會失敗。

  • w+ — 開啟檔案以供讀取和寫入。如果檔案不存在則會建立,如果檔案存在則會截斷。

  • wx+ — 與 w+ 類似,但如果路徑存在則會失敗。

  • a — 開啟檔案以供附加。如果檔案不存在則會建立。

  • ax — 與 a 類似,但如果路徑存在則會失敗。

  • a+ — 開啟檔案以供讀取和附加。如果檔案不存在則會建立。

  • ax+ — 與 a+ 類似,但如果路徑存在則會失敗。

注意

底層實作不支援使用者或群組權限。在 mode 中設定的檔案權限僅在建立檔案時使用。呼叫者一律被視為檔案的擁有者,而且僅適用這些權限。

引數
  • path (字串) – 要開啟的檔案路徑。

  • flags (字串) – 讀取和寫入旗標

  • mode

    檔案權限旗標,用於檔案。預設設定 (以八進位數字表示法) 為 0666。

傳回

一個串流物件。

FS.close(stream)

關閉檔案串流。

引數
  • stream (物件) – 要關閉的串流。

FS.llseek(stream, offset, whence)

根據 whence 參數,將串流的偏移量重新定位 offset 個位元組 (相對於檔案的開頭、目前位置或結尾)。

_llseek() 函數會根據 whence 為 SEEK_SETSEEK_CURSEEK_END,分別將與檔案描述符 fd 相關聯的開啟檔案的 offset 重新定位至 (offset_high<<32) | offset_low 位元組 (相對於檔案的開頭、檔案中的目前位置或檔案結尾)。它會以引數 result 傳回產生的檔案位置。

引數
  • stream (物件) – 要重新定位偏移量的串流。

  • offset (整數) – 相對於 whence 的偏移量 (以位元組為單位)。

  • whence (整數) – 檔案中的點 (開頭、目前點、結尾),用於計算偏移量:SEEK_SET (0)、SEEK_CUR (1) 或 SEEK_END (2)

FS.read(stream, buffer, offset, length[, position])

從串流讀取 length 個位元組,並將其儲存到從 offset 開始的 buffer 中。

預設情況下,讀取從串流的目前偏移量開始,但是,可以使用 position 引數指定特定的偏移量。例如:

var stream = FS.open('abinaryfile', 'r');
var buf = new Uint8Array(4);
FS.read(stream, buf, 0, 4, 0);
FS.close(stream);
引數
  • stream (物件) – 要從中讀取的串流。

  • buffer (ArrayBufferView) – 儲存所讀取資料的緩衝區。

  • offset (整數) – buffer 中儲存資料的偏移量。

  • length (整數) – 要寫入 buffer 的資料長度。

  • position (整數) – 要讀取的串流中的偏移量。預設情況下,這是串流的目前偏移量。

FS.write(stream, buffer, offset, length[, position])

buffer 寫入 length 個位元組 (從 offset 開始)。

預設情況下,寫入從串流的目前偏移量開始,但是,可以使用 position 引數指定特定的偏移量。例如:

var data = new Uint8Array(32);
var stream = FS.open('dummy', 'w+');
FS.write(stream, data, 0, data.length, 0);
FS.close(stream);
引數
  • stream (物件) – 要寫入的串流。

  • buffer (ArrayBufferView) – 要寫入的緩衝區。

  • offset (整數) – 要寫入的 buffer 中的偏移量。

  • length (整數) – 要寫入的資料長度。

  • position (整數) – 要寫入的串流中的偏移量。預設情況下,這是串流的目前偏移量。

FS.readFile(path, opts)

讀取位於 path 的整個檔案,並以 string (編碼為 utf8) 或新的 Uint8Array 緩衝區 (編碼為 binary) 的形式傳回。

引數
  • path (字串) – 要讀取的檔案。

  • opts (物件) –

    • encoding (字串) 定義用於回傳檔案內容的編碼:binary | utf8。預設值為 binary

    • flags (字串) 讀取旗標,定義於 FS.open()。預設值為 'r'。

傳回

檔案以 string 字串或 Uint8Array 緩衝區形式呈現,取決於編碼方式。

FS.writeFile(path, data, opts)

data 的全部內容寫入位於 path 的檔案中。例如:

FS.writeFile('file', 'foobar');
var contents = FS.readFile('file', { encoding: 'utf8' });
引數
  • path (字串) – 要寫入 data 的檔案路徑。

  • data (字串|ArrayBufferView) – 要寫入的資料。字串將永遠被解碼為 UTF-8。

  • opts (物件) –

    • flags (字串) 寫入旗標,定義於 FS.open()。預設值為 'w'。

FS.createLazyFile(parent, name, url, canRead, canWrite)

建立一個檔案,該檔案將在第一次存取時從給定的 URL 或本機檔案系統路徑延遲載入,並回傳對該檔案的參考。

警告

Firefox 和 Chrome 最近停用了同步二進制 XHR,這表示此功能無法在常規 HTML 頁面中的 JavaScript 中運作(但在 Web Workers 中可以運作)。

範例

FS.createLazyFile('/', 'foo', 'other/page.htm', true, false);
FS.createLazyFile('/', 'bar', '/get_file.php?name=baz', true, true);
引數
  • parent (字串/物件) – 父資料夾,可以是路徑(例如:'/usr/lib')或先前從 FS.mkdir()FS.createPath() 呼叫回傳的物件。

  • name (字串) – 新檔案的名稱。

  • url (字串) – 在瀏覽器中,這是存取此檔案時將回傳其內容的 URL。在像 node.js 這樣的命令列引擎中,這將是載入內容的本機(真實)檔案系統路徑。請注意,對此檔案的寫入是虛擬的。

  • canRead (布林值) – 從程式的角度來看,檔案是否應設定讀取權限。

  • canWrite (布林值) – 從程式的角度來看,檔案是否應設定寫入權限。

傳回

新檔案的參考。

FS.createPreloadedFile(parent, name, url, canRead, canWrite)

非同步預載檔案,並使用預載外掛程式來準備其內容。您應該在 preRun 中呼叫此方法,run() 將會延遲執行,直到所有預載的檔案都準備就緒。這就是當指定 --use-preload-plugins 時,preload-file 選項在 emcc 中的運作方式(如果您單獨使用此方法,則需要使用該選項來建置程式)。

引數
  • parent (字串/物件) – 父資料夾,可以是路徑(例如:'/usr/lib')或先前從 FS.mkdir()FS.createPath() 呼叫回傳的物件。

  • name (字串) – 新檔案的名稱。

  • url (字串) – 在瀏覽器中,這是當存取檔案時將回傳其內容的 URL。在命令列引擎中,這將是載入內容的本機(真實)檔案系統路徑。請注意,對此檔案的寫入是虛擬的。

  • canRead (布林值) – 從程式的角度來看,檔案是否應設定讀取權限。

  • canWrite (布林值) – 從程式的角度來看,檔案是否應設定寫入權限。

FS.trackingDelegate[callback name]

使用者可以指定回呼來接收不同的檔案系統事件。這對於追蹤檔案系統中的變更很有用。這需要 -sFS_DEBUG。

  • willMovePath — 指示路徑即將被移動。

  • onMovePath — 指示路徑已移動。

  • willDeletePath — 指示路徑即將被刪除。

  • onDeletePath — 指示路徑已刪除。

  • onOpenFile — 指示檔案已開啟。

  • onWriteToFile — 指示檔案正在寫入,以及寫入的位元組數。

  • onReadFile — 指示檔案正在讀取,以及讀取的位元組數。

  • onSeekFile — 指示在檔案中搜尋的位置和起點。

  • onCloseFile — 指示檔案正在關閉。

回呼名稱

指示檔案系統事件的回呼名稱

範例程式碼

EM_ASM(
  FS.trackingDelegate['willMovePath'] = function(oldpath, newpath) {
    out('About to move "' + oldpath + '" to "' + newpath + '"');
  };
  FS.trackingDelegate['onMovePath'] = function(oldpath, newpath) {
    out('Moved "' + oldpath + '" to "' + newpath + '"');
  };
  FS.trackingDelegate['willDeletePath'] = function(path) {
    out('About to delete "' + path + '"');
  };
  FS.trackingDelegate['onDeletePath'] = function(path) {
    out('Deleted "' + path + '"');
  };
  FS.trackingDelegate['onOpenFile'] = function(path, flags) {
    out('Opened "' + path + '" with flags ' + flags);
  };
  FS.trackingDelegate['onReadFile'] = function(path, bytesRead) {
    out('Read ' + bytesRead + ' bytes from "' + path + '"');
  };
  FS.trackingDelegate['onWriteToFile'] = function(path, bytesWritten) {
    out('Wrote to file "' + path + '" with ' + bytesWritten + ' bytes written');
  };
  FS.trackingDelegate['onSeekFile'] = function(path, position, whence) {
    out('Seek on "' + path + '" with position ' + position + ' and whence ' + whence);
  };
  FS.trackingDelegate['onCloseFile'] = function(path) {
    out('Closed ' + path);
  };
  FS.trackingDelegate['onMakeDirectory'] = function(path, mode) {
    out('Created directory ' + path + ' with mode ' + mode);
  };
  FS.trackingDelegate['onMakeSymlink'] = function(oldpath, newpath) {
    out('Created symlink from ' + oldpath + ' to ' + newpath);
  };
);

FILE *file;
file = fopen("/test.txt", "w");
fputs("hello world", file);
fclose(file);
rename("/test.txt", "/renamed.txt");
file = fopen("/renamed.txt", "r");
char str[256] = {};
fgets(str, 255, file);
printf("File read returned '%s'\n", str);
fclose(file);
remove("/renamed.txt");
mkdir("/home/test", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
symlink("/renamed.txt", "/file.txt");

範例輸出

Opened "/test.txt" with flags O_CREAT O_TRUNC O_WRONLY and file size 0
Wrote to file "/test.txt" with 11 bytes written
Wrote to file "/test.txt" with 0 bytes written
Closed /test.txt
About to move "/test.txt" to "/renamed.txt"
Moved "/test.txt" to "/renamed.txt"
Opened "/renamed.txt" with flags O_RDONLY and file size 11
Read 0 bytes from "/renamed.txt"
Read 11 bytes from "/renamed.txt"
Read 0 bytes from "/renamed.txt"
Read 0 bytes from "/renamed.txt"
Wrote to file "/dev/tty" with 31 bytes written
File read returned 'hello world'
Wrote to file "/dev/tty" with 2 bytes written
Closed /renamed.txt
About to delete "/renamed.txt"
Deleted "/renamed.txt"
Created directory "/home/test" with mode 16893
Created symlink from "/renamed.txt" to "/file.txt"

檔案類型

Emscripten 的檔案系統支援常規檔案、目錄、符號連結、字元裝置、區塊裝置和通訊端。與大多數 Unix 系統類似,所有這些檔案類型都可以使用較高層級的 FS 操作進行操作,例如 FS.read()FS.write()

FS.isFile(mode)

測試 mode 位元遮罩是否代表檔案。

引數
  • mode – 可能的檔案屬性的位元遮罩。

傳回

如果 mode 位元遮罩代表檔案,則為 true

回傳類型

布林值

FS.isDir(mode)

測試 mode 位元遮罩是否代表目錄。

傳回

如果 mode 位元遮罩代表目錄,則為 true

回傳類型

布林值

測試 mode 位元遮罩是否代表符號連結。

引數
  • mode – 可能的檔案屬性的位元遮罩。

傳回

如果 mode 位元遮罩代表符號連結,則為 true

回傳類型

布林值

FS.isChrdev(mode)

測試 mode 位元遮罩是否代表字元裝置。

引數
  • mode – 可能的檔案屬性的位元遮罩。

傳回

如果 mode 位元遮罩代表字元裝置,則為 true

回傳類型

布林值

FS.isBlkdev(mode)

測試 mode 位元遮罩是否代表區塊裝置。

引數
  • mode – 可能的檔案屬性的位元遮罩。

傳回

如果 mode 位元遮罩代表區塊裝置,則為 true

回傳類型

布林值

FS.isSocket(mode)

測試 mode 位元遮罩是否代表通訊端。

引數
  • mode – 可能的檔案屬性的位元遮罩。

傳回

如果 mode 位元遮罩代表通訊端,則為 true

回傳類型

布林值

路徑

FS.cwd()

取得目前的工作目錄。

傳回

目前的工作目錄。

FS.chdir(path)

設定目前的工作目錄。

引數
  • path (字串) – 要設定為目前工作目錄的路徑。

FS.readdir(path)

讀取 path 的內容。

引數
  • path (字串) – 輸入的路徑。

傳回

目錄中檔案名稱的陣列,包含 '.''..'

FS.lookupPath(path, opts)

查詢輸入的路徑,並回傳包含已解析路徑和節點的物件。

選項 (opts) 可讓您指定是否回傳物件、其父元件、符號連結或符號連結指向的項目。例如:

var lookup = FS.lookupPath(path, { parent: true });
引數
  • path (字串) – 輸入的路徑。

  • opts (物件) –

    路徑的選項

    • parent (布林值) 如果為 true,則一旦到達倒數第二個元件,就會停止解析路徑。例如,路徑 /foo/bar 使用 { parent: true } 會回傳代表 /foo 的物件。預設值為 false

    • follow (布林值) 如果為 true,則如果最後一個元件是符號連結,則會追蹤它。例如,考慮一個連結到 /foo/notes.txt 的符號連結 /foo/symlink。如果 { follow: true },則會回傳代表 /foo/notes.txt 的物件。如果 { follow: false },則會回傳代表符號連結檔案的物件。預設值為 false

傳回

具有以下格式的物件

{
  path: resolved_path,
  node: resolved_node
}

FS.analyzePath(path, dontResolveLastLink)

查詢傳入的路徑並返回一個包含檔案狀態和節點資訊的物件。基於 FS.lookupPath 構建,並提供有關給定路徑及其父級的更多資訊。如果發生任何錯誤,它不會拋出例外,而是返回一個 error 屬性。

引數
  • path (字串) – 輸入的路徑。

  • dontResolveLastLink (布林值) – 如果為 true,則如果最後一個組件是符號連結,則不追蹤它。

傳回

具有以下格式的物件

{
  isRoot: boolean,
  exists: boolean,
  error: Error,
  name: string,
  path: resolved_path,
  object: resolved_node,
  parentExists: boolean,
  parentPath: resolved_parent_path,
  parentObject: resolved_parent_node
}

FS.getPath(node)

取得 node 的絕對路徑,並考慮到掛載點。

引數
  • node – 目前的節點。

傳回

node 的絕對路徑。