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.
Applications compiled with Emscripten usually expect synchronous I/O, so Emscripten itself provides file systems with completely synchronous interfaces.
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 is the default file system mounted at / when the runtime is initialized. All files exist strictly in-memory, and any data written to them is lost when the page is reloaded.
Note
This file system is only for use when running inside node.js.
This file system lets a program in node directly access files on the local file system, as if the program were running normally. It uses node’s synchronous FS API to immediately persist any data written to the Emscripten file system to your local disk.
See this test for an example.
Note
This file system is only for use when running code inside a browser.
The IDBFS file system implements the FS.syncfs() interface, which when called will persist any operations to an IndexedDB instance.
This is provided to overcome the limitation that browsers do not offer synchronous APIs for persistent storage, and so (by default) all writes exist only temporarily in-memory.
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.
Converts a major and minor number into a single unique integer. This is used as an id to represent the device.
Arguments: |
|
---|
Registers the specified device driver with a set of callbacks.
Arguments: |
|
---|
Emscripten standard I/O works by going though the virtual /dev/stdin, /dev/stdout and /dev/stderr devices. You can set them up using your own I/O functions by calling FS.init().
By default:
Note
All the configuration should be done before the main run() method is executed, typically by implementing Module.preRun. See Interacting with code for more information.
Sets up standard I/O devices for stdin, stdout, and stderr.
The devices are set up using the following (optional) callbacks. If any of the callbacks throw an exception, it will be caught and handled as if the device malfunctioned.
Arguments: |
|
---|
Mounts the FS object specified by type to the directory specified by mountpoint. The opts object is specific to each file system type.
Arguments: |
|
---|
Unmounts the specified mountpoint.
Arguments: |
|
---|
Responsible for iterating and synchronizing all mounted file systems in an asynchronous fashion.
Note
Currently, only the IDBFS file system implements the interfaces needed for synchronization. All other file systems are completely synchronous and don’t require synchronization.
The populate flag is used to control the intended direction of the underlying synchronization between Emscripten`s internal data, and the file system’s persistent data.
For example:
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
});
}
A real example of this functionality can be seen in test_idbfs_sync.c.
Arguments: |
|
---|
Creates a new directory node in the file system. For example:
FS.mkdir('/data');
Note
The underlying implementation does not support user or group permissions. The caller is always treated as the owner of the folder, and only permissions relevant to the owner apply.
Arguments: |
|
---|
Creates a new device node in the file system referencing the registered device driver (FS.registerDevice()) for dev. For example:
var id = FS.makedev(64, 0);
FS.registerDevice(id, {});
FS.mkdev('/dummy', id);
Arguments: |
|
---|
Creates a symlink node at newpath linking to oldpath. For example:
FS.writeFile('file', 'foobar');
FS.symlink('file', 'link');
Arguments: |
|
---|
Renames the node at oldpath to newpath. For example:
FS.writeFile('file', 'foobar');
FS.rename('file', 'newfile');
Arguments: |
|
---|
Removes an empty directory located at path.
Example
FS.mkdir('data');
FS.rmdir('data');
Arguments: |
|
---|
Unlinks the node at path.
This removes a name from the file system. If that name was the last link to a file (and no processes have the file open) the file is deleted.
For example:
FS.writeFile('/foobar.txt', 'Hello, world');
FS.unlink('/foobar.txt');
Arguments: |
|
---|
Gets the string value stored in the symbolic link at path. For example:
#include <stdio.h>
#include <emscripten.h>
int main() {
EM_ASM(
FS.writeFile('file', 'foobar');
FS.symlink('file', 'link');
console.log(FS.readlink('link'));
);
return 0;
}
outputs
file
Arguments: |
|
---|---|
Returns: | The string value stored in the symbolic link at path. |
Gets a JavaScript object containing statistics about the node at path. For example:
#include <stdio.h>
#include <emscripten.h>
int main() {
EM_ASM(
FS.writeFile('file', 'foobar');
console.log(FS.stat('file'));
);
return 0;
}
outputs
{
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
}
Arguments: |
|
---|
Identical to FS.stat(), However, if path is a symbolic link then the returned stats will be for the link itself, not the file that it links to.
Arguments: |
|
---|
Change the mode flags for path to mode.
Note
The underlying implementation does not support user or group permissions. The caller is always treated as the owner of the folder, and only permissions relevant to the owner apply.
For example:
FS.writeFile('forbidden', 'can\'t touch this');
FS.chmod('forbidden', 0000);
Arguments: |
|
---|
Identical to FS.chmod(). However, if path is a symbolic link then the mode will be set on the link itself, not the file that it links to.
Arguments: |
|
---|
Identical to FS.chmod(). However, a raw file descriptor is supplied as fd.
Arguments: |
|
---|
Change the ownership of the specified file to the given user or group id.
Note
This call exists to provide a more “complete” API mapping for ported code. Values set are effectively ignored.
Arguments: |
|
---|
Identical to FS.chown(). However, if path is a symbolic link then the properties will be set on the link itself, not the file that it links to.
Note
This call exists to provide a more “complete” API mapping for ported code. Values set are effectively ignored.
Arguments: |
|
---|
Identical to FS.chown(). However, a raw file descriptor is supplied as fd.
Note
This call exists to provide a more “complete” API mapping for ported code. Values set are effectively ignored.
Arguments: |
|
---|
Truncates a file to the specified length. For example:
#include <stdio.h>
#include <emscripten.h>
int main() {
EM_ASM(
FS.writeFile('file', 'foobar');
FS.truncate('file', 3);
console.log(FS.readFile('file', { encoding: 'utf8' }));
);
return 0;
}
outputs
foo
Arguments: |
|
---|
Truncates the file identified by the fd to the specified length (len).
Arguments: |
|
---|
Change the timestamps of the file located at path. The times passed to the arguments are in milliseconds since January 1, 1970 (midnight UTC/GMT).
Note that in the current implementation the stored timestamp is a single value, the maximum of atime and mtime.
Arguments: |
|
---|
Opens a file with the specified flags. flags can be:
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.
Arguments: |
|
---|---|
Returns: | A stream object. |
Closes the file stream.
Arguments: |
|
---|
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: |
|
---|
Read length bytes from the stream, storing them into buffer starting at offset.
By default, reading starts from the stream’s current offset, however, a specific offset can be specified with the position argument. For example:
var stream = FS.open('abinaryfile', 'r');
var buf = new Uint8Array(4);
FS.read(stream, buf, 0, 4, 0);
FS.close(stream);
Arguments: |
|
---|
Writes length bytes from buffer, starting at offset.
By default, writing starts from the stream’s current offset, however, a specific offset can be specified with the position argument. For example:
var data = new Uint8Array(32);
var stream = FS.open('dummy', 'w+');
FS.write(stream, data, 0, data.length, 0);
FS.close(stream);
Arguments: |
|
---|
Reads the entire file at path and returns it as a string (encoding is utf8), or as a new Uint8Array buffer (encoding is binary).
Arguments: |
|
---|---|
Returns: | The file as a string or Uint8Array buffer, depending on the encoding. |
Writes the entire contents of data to the file at path.
The value of opts determines whether data is treated either as a string (encoding = utf8), or as an ArrayBufferView (encoding = binary). For example:
FS.writeFile('file', 'foobar');
var contents = FS.readFile('file', { encoding: ``utf8`` });
Arguments: |
|
---|
Creates a file that will be loaded lazily on first access from a given URL or local file system path, and returns a reference to it.
Warning
Firefox and Chrome have recently disabled synchronous binary XHRs, which means this cannot work for JavaScript in regular HTML pages (but it works within Web Workers).
Example
FS.createLazyFile('/', 'foo', 'other/page.htm', true, false);
FS.createLazyFile('/', 'bar', '/get_file.php?name=baz', true, true);
Arguments: |
|
---|---|
Returns: | A reference to the new file. |
Preloads a file asynchronously. 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.
Arguments: |
|
---|
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().
Tests if the mode bitmask represents a file.
Arguments: |
|
---|---|
Returns: | true if the mode bitmask represents a file. |
Return type: | bool |
Tests if the mode bitmask represents a directory.
Returns: | true if the mode bitmask represents a directory. |
---|---|
Return type: | bool |
Tests if the mode bitmask represents a symlink.
Arguments: |
|
---|---|
Returns: | true if the mode bitmask represents a symlink. |
Return type: | bool |
Tests if the mode bitmask represents a character device.
Arguments: |
|
---|---|
Returns: | true if the mode bitmask represents a character device. |
Return type: | bool |
Tests if the mode bitmask represents a block device.
Arguments: |
|
---|---|
Returns: | true if the mode bitmask represents a block device. |
Return type: | bool |
Tests if the mode bitmask represents a socket.
Arguments: |
|
---|---|
Returns: | true if the mode bitmask represents a socket. |
Return type: | bool |
Gets the current working directory.
Returns: | The current working directory. |
---|
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, it’s parent component, a symlink, or the item the symlink points to are returned. For example:
var lookup = FS.lookupPath(path, { parent: true });
Arguments: |
|
---|---|
Returns: | an object with the format: {
path: resolved_path,
node: resolved_node
}
|
Gets the absolute path to node, accounting for mounts.
Arguments: |
|
---|---|
Returns: | The absolute path to node. |