File operations in Emscripten are provided by the FS library. It is used internally for all of Emscripten’s libc and libcxx file I/O.

Note

The API is inspired by the Linux/POSIX File System API, with each presenting a very similar interface.

The underlying behaviour is also similar, except where differences between the native and browser environments make this unreasonable. For example, user and group permissions are defined but ignored in FS.open().

Emscripten predominantly compiles code that uses synchronous file I/O, so the majority of the FS member functions offer a synchronous interface (with errors being reported by raising exceptions of type FS.ErrnoError).

File data in Emscripten is partitioned by mounted file systems. Several file systems are provided. An instance of MEMFS is mounted to / by default. Instances of NODEFS and IDBFS can be mounted to other directories if your application needs to persist data.

The automatic tests in tests/test_core.py (search for test_files) contain many examples of how to use this API. The tutorial also shows how to pre-load a file so that it can be read from compiled C/C++.

A high level overview of the way File Systems work in Emscripten-ported code is provided in the File System Overview.

Emscripten decides whether to include file system support automatically. Many programs don’t need files, and file system support is not negligible in size, so Emscripten avoids including it when it doesn’t see a reason to. That means that if your C/C++ code does not access files, then the FS object and other file system APIs will not be included in the output. And, on the other hand, if your C/C++ code does use files, then file system support will be automatically included. So normally things will “just work” and you don’t need to think about this at all.

However, if your C/C++ code doesn’t use files, but you want to use them from JavaScript, then you can build with -sFORCE_FILESYSTEM=1, which will make the compiler include file system support even though it doesn’t see it being used.

However, due to JavaScript’s event-driven nature, most persistent storage options offer only asynchronous interfaces. Emscripten offers multiple file systems that can be mounted with FS.mount() to help deal with persistence depending on the execution context.

This file system lets a program in node map directories (via a mount operation) on the host filesystem to directories in Emscripten’s virtual filesystem. It uses node’s synchronous FS API to immediately persist any data written to the Emscripten file system to your local disk.

Emscripten supports registering arbitrary device drivers composed of a device id and a set of device-specific stream callbacks. Once a driver has been registered with FS.registerDevice(), a device node can be created to reference it (using FS.mkdev()).

The device node acts as an interface between the device and the file system. Any stream referencing the new node will inherit the stream callbacks registered for the device, making all of the high-level FS operations transparently interact with the device.

Note

Every device is different and unique. While common file operations like open, close, read, and write are typically supported (and inherited by file streams to provide a layer of abstraction for the equivalent libc functions to call), each device should implement whatever callbacks it needs based on its unique characteristics.

populate (bool) – true to initialize Emscripten’s file system data with the data from the file system’s persistent source, and false to save Emscripten`s file system data to the file system’s persistent source.

callback – A notification callback function that is invoked on completion of the synchronization. If an error occurred, it will be provided as a parameter to this function.

w+ — Open file for reading and writing. The file is created if it does not exist or truncated if it exists.

wx+ — Like w+ but fails if path exists.

a — Open file for appending. The file is created if it does not exist.

ax — Like a but fails if path exists.

a+ — Open file for reading and appending. The file is created if it does not exist.

ax+ — Like a+ but fails if path exists.

Note

The underlying implementation does not support user or group permissions. The file permissions set in mode are only used if the file is created. The caller is always treated as the owner of the file, and only those permissions apply.

Repositions the offset of the stream offset bytes relative to the beginning, current position, or end of the file, depending on the whence parameter.

The _llseek() function repositions the offset of the open file associated with the file descriptor fd to (offset_high<<32)|offset_low bytes relative to the beginning of the file, the current position in the file, or the end of the file, depending on whether whence is SEEK_SET, SEEK_CUR, or SEEK_END, respectively. It returns the resulting file position in the argument result.

Arguments:

stream (object) – The stream for which the offset is to be repositioned.

offset (int) – The offset (in bytes) relative to whence.

whence (int) – Point in file (beginning, current point, end) from which to calculate the offset: SEEK_SET (0), SEEK_CUR (1) or SEEK_END (2)

parent (string/object) – The parent folder, either as a path (e.g. ‘/usr/lib’) or an object previously returned from a FS.createFolder() or FS.createPath() call.

name (string) – The name of the new file.

url (string) – In the browser, this is the URL whose contents will be returned when this file is accessed. In a command line engine like node.js, this will be the local (real) file system path from where the contents will be loaded. Note that writes to this file are virtual.

canRead (bool) – Whether the file should have read permissions set from the program’s point of view.

canWrite (bool) – Whether the file should have write permissions set from the program’s point of view.

Preloads a file asynchronously, and uses preload plugins to prepare its content. You should call this in preRun, run() will be delayed until all preloaded files are ready. This is how the preload-file option works in emcc when --use-preload-plugins has been specified (if you use this method by itself, you will need to build the program with that option).

Arguments:

parent (string/object) – The parent folder, either as a path (e.g. ‘/usr/lib’) or an object previously returned from a FS.createFolder() or FS.createPath() call.

name (string) – The name of the new file.

url (string) – In the browser, this is the URL whose contents will be returned when the file is accessed. In a command line engine, this will be the local (real) file system path the contents will be loaded from. Note that writes to this file are virtual.

canRead (bool) – Whether the file should have read permissions set from the program’s point of view.

canWrite (bool) – Whether the file should have write permissions set from the program’s point of view.

Emscripten’s file system supports regular files, directories, symlinks, character devices, block devices and sockets. Similarly to most Unix systems, all of these file types can be operated on using the higher-level FS operations like FS.read() and FS.write().

Looks up the incoming path and returns an object containing both the resolved path and node.

The options (opts) allow you to specify whether the object, its parent component, a symlink, or the item the symlink points to are returned. For example:

varlookup=FS.lookupPath(path,{parent:true});

Arguments:

path (string) – The incoming path.

opts (object) –

Options for the path:

parent (bool)

If true, stop resolving the path once the penultimate component is reached.
For example, the path /foo/bar with {parent:true} would return an object representing /foo. The default is false.

follow (bool)

If true, follow the last component if it is a symlink.
For example, consider a symlink /foo/symlink that links to /foo/notes.txt. If {follow:true}, an object representing /foo/notes.txt would be returned. If {follow:false}, an object representing the symlink file would be returned. The default is false.