Emscripten 中的文件操作由 FS 库提供。它被用于 Emscripten 的所有 libc 和 libcxx 文件 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()。如果您的应用程序需要 持久化数据,则可以将 NODEFS 和 IDBFS 的实例挂载到其他目录。
test/test_core.py 中的自动测试(搜索 test_files
)包含许多关于如何使用此 API 的示例。教程 还演示了如何预加载文件,以便可以从编译后的 C/C++ 中读取它。
文件系统概述 提供了 Emscripten 移植代码中文件系统工作方式的高级概述。
注意
当前状态:开发中
WasmFS 是一个高性能的、完全多线程的、基于 WebAssembly 的 Emscripten 文件系统层,它将取代现有的 JavaScript 版本。
基于 JavaScript 的文件系统最初是在支持 pthreads 之前编写的,当时在 JS 中编写代码更优化。因此,它在 pthreads 构建中存在开销,因为我们必须代理到主线程,在那里执行所有文件系统操作。WasmFS 相反,被编译成 Wasm,并具有完全的多线程支持。它还旨在更模块化和可扩展。
您可能会注意到与原始 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
构建,这将使编译器即使它没有看到它被使用,也会包含文件系统支持。
另一方面,如果您希望不包含任何文件系统支持代码(即使由于 printf 或 iostreams,也可能会包含,因为 musl 和 libc++ 的结构方式),您可以使用 -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) 明确启用。
这是运行时初始化时默认挂载到 /
的文件系统。所有文件都严格存在于内存中,写入它们的所有数据在页面重新加载时都会丢失。
注意
此文件系统仅在 node.js 内部运行时使用。
此文件系统允许node 中的程序将主机文件系统上的目录(通过挂载操作)映射到 Emscripten 的虚拟文件系统中的目录。它使用 node 的同步 FS API 将写入 Emscripten 文件系统的任何数据立即持久化到本地磁盘。
请参阅 此测试 以获取示例。
注意
此文件系统仅在 node.js 内部运行时使用。
这是一个特殊的后端,因为它用直接的 Node.js 操作替换了所有正常的 FS 访问,而无需执行 FS.mount()。初始工作目录将与 process.cwd() 相同,而不是 VFS 根目录。因为此模式直接使用 Node.js 访问您操作系统上的真实本地文件系统,因此代码不一定是跨操作系统的可移植的 - 它将与 Node.js 程序一样可移植,这意味着底层操作系统处理权限和错误的方式等方面的差异可能会很明显。到目前为止,这主要是在 Linux 上测试的。
请参阅 此 关于 NODEFS 的部分,您可以在其中看到一个挂载操作 - 这在 NODERAWFS 中是不需要的。
注意
此文件系统仅供在浏览器中运行代码时使用。
IDBFS 文件系统实现 FS.syncfs()
接口,该接口在调用时会将所有操作持久化到 IndexedDB
实例中。
提供此功能是为了克服浏览器不提供持久存储的同步 API 的限制,因此(默认情况下)所有写入仅暂时存在于内存中。
如果在挂载 IDBFS 时传递了挂载选项 autoPersist: true,则无论何时对 IDBFS 目录树进行任何更改,这些更改都会自动持久化到 IndexedDB 后端。 这使得用户无需手动调用 FS.syncfs 来将更改持久化到挂载的 IDBFS 目录树。
注意
此文件系统仅供在工作线程中运行代码时使用。
此文件系统提供对工作线程内 File
和 Blob
对象的只读访问,无需将整个数据复制到内存中,并且可以潜在地用于处理大型文件。
这允许一个模块挂载另一个模块的文件系统。 当不同的模块需要共享文件系统而无需手动同步文件内容时,这很有用。 例如
// 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 操作透明地与设备交互。
注意
每个设备都不同且独一无二。 虽然通常支持常见的文件操作,如 open
、close
、read
和 write
(并且由文件流继承,以便为等效的 libc 函数调用提供抽象层),但每个设备都应根据其独特的特征实现其所需的回调。
FS.
makedev
(ma, mi)¶将主次编号转换为单个唯一的整数。 这是用作代表设备的 ID。
ma – 主编号。
mi – 次编号。
FS.
registerDevice
(dev, ops)¶使用一组回调注册指定的设备驱动程序。
dev – 使用 makedev()
创建的特定设备驱动程序 ID。
ops (object) – 设备所需的回调集。 例如,请参阅 NODEFS 默认回调。
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)¶为 stdin
、stdout
和 stderr
设置标准 I/O 设备。
这些设备使用以下(可选)回调设置。 如果任何回调抛出异常,它将被捕获并处理,就像设备出现故障一样。
input – 输入回调。 每当程序尝试从 stdin
读取数据时,将调用此回调,且不带任何参数。 当数据可用时,它应返回 ASCII 字符代码,当数据不可用时,它应返回 null
。
output – 输出回调。 每当程序写入 stdout
时,将调用此回调,并传入 ASCII 字符代码。 它还可以使用 null
来刷新输出。
error – 错误回调。 这与 output
相似,不同之处在于,当数据写入 stderr
时,将调用它。
注意
从 libc 派生的函数,如 FS.readdir()
,使用全小写名称,而添加的函数,如 FS.readFile()
,使用驼峰式命名。
FS.
mount
(type, opts, mountpoint)¶将由 type
指定的 FS 对象挂载到由 mountpoint
指定的目录。 opts
对象特定于每种文件系统类型。
type – 文件系统类型: MEMFS
、NODEFS
、IDBFS
或 WORKERFS
。
opts (object) –
底层文件系统使用的通用设置对象。
NODEFS
使用 root 参数将 Emscripten 目录映射到物理目录。 例如,要将当前文件夹作为 NODEFS 实例挂载
FS.mkdir('/working');
FS.mount(NODEFS, { root: '.' }, '/working');
WORKERFS
接受 files 和 blobs 参数,将提供的文件扁平列表映射到 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 (string) – 文件系统要挂载到的现有本地 Emscripten 目录的路径。 它可以是绝对路径,也可以是相对于当前目录的路径。
FS.
unmount
(mountpoint)¶卸载指定的 mountpoint
。
mountpoint (string) – 要卸载的目录。
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 (bool) – true
表示使用文件系统的持久数据源中的数据初始化 Emscripten 的文件系统数据,而 false
表示将 Emscripten 的文件系统数据保存到文件系统的持久数据源。
callback – 在同步完成后调用的通知回调函数。 如果发生错误,它将作为参数提供给此函数。
FS.
mkdir
(path, mode)¶在文件系统中创建新的目录节点。 例如
FS.mkdir('/data');
注意
底层实现不支持用户或组权限。 调用者始终被视为文件夹的所有者,并且只有与所有者相关的权限适用。
FS.
mkdev
(path, mode, dev)¶在文件系统中创建一个新的设备节点,引用已注册的设备驱动程序 (FS.registerDevice()
),用于 dev
。例如
var id = FS.makedev(64, 0);
FS.registerDevice(id, {});
FS.mkdev('/dummy', id);
FS.
symlink
(oldpath, newpath)¶在 newpath
创建一个指向 oldpath
的符号链接节点。例如
FS.writeFile('file', 'foobar');
FS.symlink('file', 'link');
oldpath (string) – 要链接到的文件的路径名。
newpath (string) – 指向 oldpath
的新符号链接节点的路径。
FS.
rename
(oldpath, newpath)¶将 oldpath
的节点重命名为 newpath
。例如
FS.writeFile('file', 'foobar');
FS.rename('file', 'newfile');
oldpath (string) – 旧的路径名。
newpath (string) – 新的路径名
FS.
rmdir
(path)¶删除位于 path
的空目录。
示例
FS.mkdir('data');
FS.rmdir('data');
path (string) – 要删除的目录的路径。
FS.
unlink
(path)¶解除 path
的节点链接。
这将从文件系统中删除一个名称。如果该名称是文件的最后一个链接(并且没有进程打开该文件),则该文件将被删除。
例如
FS.writeFile('/foobar.txt', 'Hello, world');
FS.unlink('/foobar.txt');
path (string) – 目标节点的路径。
FS.
readlink
(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 (string) – 目标文件的路径。
存储在 path
的符号链接中的字符串值。
FS.
stat
(path)¶获取一个 JavaScript 对象,其中包含关于 path
的节点的统计信息。例如
#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 (string) – 目标文件的路径。
FS.
lstat
(path)¶与 FS.stat()
相同,但是,如果 path
是一个符号链接,则返回的统计信息将是链接本身的统计信息,而不是它链接到的文件的统计信息。
path (string) – 目标文件的路径。
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 (string) – 目标文件的路径。
uid (int) – 获取文件所属权的用户 ID。
gid (int) – 获取文件所属权的组 ID。
FS.
lchown
(path, uid, gid)¶与 FS.chown()
相同。但是,如果 path
是一个符号链接,则属性将设置在链接本身,而不是它链接到的文件。
注意
此调用存在是为了为移植的代码提供更“完整”的 API 映射。设置的值实际上被忽略。
path (string) – 目标文件的路径。
uid (int) – 获取文件所属权的用户 ID。
gid (int) – 获取文件所属权的组 ID。
FS.
fchown
(fd, uid, gid)¶与 FS.chown()
相同。但是,一个原始文件描述符作为 fd
提供。
注意
此调用存在是为了为移植的代码提供更“完整”的 API 映射。设置的值实际上被忽略。
fd (int) – 目标文件的描述符。
uid (int) – 获取文件所属权的用户 ID。
gid (int) – 获取文件所属权的组 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 (string) – 要截断的文件的路径。
len (int) – 文件的截断长度。
FS.
ftruncate
(fd, len)¶将由 fd
标识的文件截断为指定的长度 (len
)。
fd (int) – 要截断的文件的描述符。
len (int) – 文件的截断长度。
FS.
utime
(path, atime, mtime)¶更改位于 path
的文件的时间戳。传递给参数的时间是以 1970 年 1 月 1 日(午夜 UTC/GMT)以来的毫秒为单位。
请注意,在当前实现中,存储的时间戳是一个单一值,即 atime
和 mtime
的最大值。
path (string) – 要更新的文件的路径。
atime (int) – 文件访问时间(毫秒)。
mtime (int) – 文件修改时间(毫秒)。
FS.
open
(path, flags[, mode])¶使用指定的标志打开文件。 flags
可以是
r
— 打开文件以供读取。
r+
— 打开文件以供读取和写入。
w
— 打开文件以供写入。
wx
— 与 w
相同,但如果路径存在则失败。
w+
— 打开文件以供读取和写入。如果文件不存在,则创建该文件;如果文件存在,则将其截断。
wx+
— 与 w+
相同,但如果路径存在则失败。
a
— 打开文件以供追加。如果文件不存在,则创建该文件。
ax
— 与 a
相同,但如果路径存在则失败。
a+
— 打开文件以供读取和追加。如果文件不存在,则创建该文件。
ax+
— 与 a+
相同,但如果路径存在则失败。
注意
底层实现不支持用户或组权限。在 mode
中设置的文件权限仅在创建文件时使用。调用者始终被视为文件的拥有者,并且只应用那些权限。
FS.
close
(stream)¶关闭文件流。
stream (object) – 要关闭的流。
FS.
llseek
(stream, offset, whence)¶根据 whence
参数,将流 offset
的偏移量相对于文件开头、当前位置或文件末尾重新定位 offset
字节。
_llseek()
函数将与文件描述符 fd
关联的打开文件的 offset
重新定位到 (offset_high<<32) | offset_low
字节,相对于文件开头、文件中的当前位置或文件末尾,取决于 whence
分别是 SEEK_SET
、SEEK_CUR
还是 SEEK_END
。它将返回参数结果中的最终文件位置。
stream (object) – 要重新定位偏移量的流。
offset (int) – 相对于 whence
的偏移量(以字节为单位)。
whence (int) – 文件中要计算偏移量的点(开头、当前点、末尾):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 (object) – 要从中读取的流。
buffer (ArrayBufferView) – 用于存储读取数据的缓冲区。
offset (int) – 在 buffer
中存储数据的偏移量。
length (int) – 要写入 buffer
的数据长度。
position (int) – 要读取的流中的偏移量。默认情况下,这是流的当前偏移量。
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 (object) – 要写入的流。
buffer (ArrayBufferView) – 要写入的缓冲区。
offset (int) – 在 buffer
中写入的偏移量。
length (int) – 要写入的数据长度。
position (int) – 要写入的流中的偏移量。默认情况下,这是流的当前偏移量。
FS.
readFile
(path, opts)¶读取 path
处的整个文件,并将其作为 string
(编码为 utf8
)或新的 Uint8Array
缓冲区(编码为 binary
)返回。
path (string) – 要读取的文件。
opts (object) –
encoding (string) 定义用于返回文件内容的编码:binary
| utf8
。默认值为 binary
flags (string) 读取标志,如 FS.open()
中所定义。默认值为 'r'。
文件作为 string
或 Uint8Array
缓冲区,具体取决于编码。
FS.
writeFile
(path, data, opts)¶将 data
的整个内容写入 path
处的文件。例如
FS.writeFile('file', 'foobar');
var contents = FS.readFile('file', { encoding: 'utf8' });
path (string) – 要写入 data
的文件。
data (string|ArrayBufferView) – 要写入的数据。字符串将始终被解码为 UTF-8。
opts (object) –
flags (string) 写入标志,如 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 (string/object) – 父文件夹,可以是路径(例如 ‘/usr/lib’)或先前从 FS.mkdir() 或 FS.createPath() 调用返回的对象。
name (string) – 新文件的名称。
url (string) – 在浏览器中,这是当访问此文件时将返回其内容的 URL。在命令行引擎(如 node.js)中,这将是内容将从其加载的本地(实际)文件系统路径。请注意,写入此文件是虚拟的。
canRead (bool) – 文件是否应该从程序的角度设置读取权限。
canWrite (bool) – 文件是否应该从程序的角度设置写入权限。
对新文件的引用。
FS.
createPreloadedFile
(parent, name, url, canRead, canWrite)¶异步预加载文件,并使用预加载插件准备其内容。您应该在 preRun
中调用此方法,run()
将延迟到所有预加载文件准备就绪后才执行。这就是当指定 --use-preload-plugins
时,emcc 中的 preload-file 选项的工作方式(如果您单独使用此方法,您将需要使用该选项构建程序)。
parent (string/object) – 父文件夹,可以是路径(例如 ‘/usr/lib’)或先前从 FS.mkdir() 或 FS.createPath() 调用返回的对象。
name (string) – 新文件的名称。
url (string) – 在浏览器中,这是当访问文件时将返回其内容的 URL。在命令行引擎中,这将是内容将从其加载的本地(实际)文件系统路径。请注意,写入此文件是虚拟的。
canRead (bool) – 文件是否应该从程序的角度设置读取权限。
canWrite (bool) – 文件是否应该从程序的角度设置写入权限。
FS.
trackingDelegate[callback name]
¶用户可以指定回调以接收不同的文件系统事件。这对于跟踪文件系统中的更改很有用。这需要 -sFS_DEBUG。
willMovePath
— 表示路径即将被移动。
onMovePath
— 表示路径已移动。
willDeletePath
— 表示路径即将被删除。
onDeletePath
— 表示路径已删除。
onOpenFile
— 表示文件已打开。
onWriteToFile
— 表示文件正在被写入,以及写入的字节数。
onReadFile
— 表示文件正在被读取,以及读取的字节数。
onSeekFile
— 表示在文件中进行查找,包括位置和 whence。
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 – 可能的文件属性的位掩码。
true
如果 mode
位掩码表示文件。
bool
FS.
isDir
(mode)¶测试 mode
位掩码是否表示目录。
true
如果 mode
位掩码表示目录。
bool
FS.
isLink
(mode)¶测试 mode
位掩码是否表示符号链接。
mode – 可能的文件属性的位掩码。
true
如果 mode
位掩码表示符号链接。
bool
FS.
isChrdev
(mode)¶测试 mode
位掩码是否表示字符设备。
mode – 可能的文件属性的位掩码。
true
如果 mode
位掩码表示字符设备。
bool
FS.
isBlkdev
(mode)¶测试 mode
位掩码是否表示块设备。
mode – 可能的文件属性的位掩码。
true
如果 mode
位掩码表示块设备。
bool
FS.
isSocket
(mode)¶测试 mode
位掩码是否表示套接字。
mode – 可能的文件属性的位掩码。
true
如果 mode
位掩码表示套接字。
bool
FS.
cwd
()¶获取当前工作目录。
当前工作目录。
FS.
chdir
(path)¶设置当前工作目录。
path (string) – 要设置为当前工作目录的路径。
FS.
readdir
(path)¶读取 path
的内容。
path (string) – 输入路径。
目录中文件的名称数组,包括 '.'
和 '..'
。
FS.
lookupPath
(path, opts)¶查找输入路径并返回一个包含已解析路径和节点的对象。
选项 (opts
) 允许您指定是否返回对象、其父组件、符号链接或符号链接指向的项目。例如
var lookup = FS.lookupPath(path, { parent: true });
path (string) – 输入路径。
opts (object) –
路径的选项
parent (bool) 如果为 true,则在到达倒数第二个组件时停止解析路径。例如,路径 /foo/bar
与 { parent: true }
将返回一个表示 /foo
的对象。默认值为 false
。
follow (bool) 如果为 true,则如果最后一个组件是符号链接,则跟踪该组件。例如,考虑一个符号链接 /foo/symlink
,它链接到 /foo/notes.txt
。如果 { follow: true }
,则会返回一个表示 /foo/notes.txt
的对象。如果 { follow: false }
,则会返回一个表示符号链接文件的对象。默认值为 false
。
具有以下格式的对象
{
path: resolved_path,
node: resolved_node
}
FS.
analyzePath
(path, dontResolveLastLink)¶查找输入路径并返回一个包含有关文件统计信息和节点的信息的对象。构建在 FS.lookupPath
之上,并提供有关给定路径及其父级的更多信息。如果发生任何错误,它不会抛出,而是返回一个 error
属性。
path (string) – 输入路径。
dontResolveLastLink (boolean) – 如果为 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
的绝对路径。