![NPM](https://nodei.co/npm/filer.png?downloads=true&stars=true)
![codecov](https://codecov.io/gh/filerjs/filer/branch/master/graph/badge.svg)
Filer
Filer is a POSIX-like file system for browsers.
Compatibility
Filer is known to work in the following browsers/versions, with the specified Storage Providers:
- node.js: v0.10.*+
- IE: 10+ (IndexedDB)
- Firefox: 26+ (IndexedDB)
- Chrome: 31+ (IndexedDB, WebSQL)
- Safari: 7.0+ (WebSQL)
- Opera: 19+ (IndexedDB, WebSQL)
- iOS: 3.2+ (WebSQL)
- Android Browser: 2.1-4.4 (WebSQL), 4.4+ (IndexedDB)
NOTE: if you're interested in maximum compatibility, use the Fallback
provider instead of Default
.
See the section on Storage Providers.
Contributing
Want to join the fun? We'd love to have you! See CONTRIBUTING.
How to Get It
Filer can be obtained in a number of ways:
- Via npm:
npm install filer
- Via unpkg:
<script src="https://unpkg.com/filer"></script>
or specify a version directly, for example: https://unpkg.com/filer@1.0.1/dist/filer.min.js
Loading and Usage
Filer is built as a UMD module and can therefore be loaded as a CommonJS or AMD module, or used via the global.
var Filer = require('filer');
requirejs.config({
baseUrl: '/',
paths: {
'filer': 'filer/dist/filer'
}
});
requirejs(['filer'], function(Filer) {...}
var Filer = window.Filer;
Getting Started
Filer is as close to the node.js fs module as possible,
with the following differences:
- No synchronous versions of methods (e.g.,
mkdir()
but not mkdirSync()
). - No support for stream-based operations (e.g.,
fs.ReadStream
, fs.WriteStream
).
Filer has other features lacking in node.js (e.g., swappable backend
storage providers, extended attributes, etc).
Like node.js, the API is asynchronous and most methods expect the caller to provide
a callback function (note: like node.js, Filer will supply one if it's missing).
Errors are passed to callbacks through the first parameter. As with node.js,
there is no guarantee that file system operations will be executed in the order
they are invoked. Ensure proper ordering by chaining operations in callbacks.
Overview
To create a new file system or open an existing one, create a new FileSystem
instance. By default, a new IndexedDB
database is created for each file system. The file system can also use other
backend storage providers, for example WebSQL
or even RAM (i.e., for temporary storage). See the section on Storage Providers.
var fs = new Filer.FileSystem();
fs.open('/myfile', 'w+', function(err, fd) {
if (err) throw err;
fs.close(fd, function(err) {
if (err) throw err;
fs.stat('/myfile', function(err, stats) {
if (err) throw err;
console.log('stats: ' + JSON.stringify(stats));
});
});
});
For a complete list of FileSystem
methods and examples, see the FileSystem Instance Methods
section below.
Filer also includes node's path
and Buffer
modules. See the Filer.Path and Filer.Buffer sections below.
In addition, common shell operations (e.g., rm, touch, cat, etc.) are supported via the
FileSystemShell
object, which can be obtained from, and used with a FileSystem
.
See theFileSystemShell section below.
API Reference
Like node.js, callbacks for methods that accept them are optional but suggested (i.e., if
you omit the callback, errors will be thrown as exceptions). The first callback parameter is
reserved for passing errors. It will be null
if no errors occurred and should always be checked.
Support for Promises
The Promise based API mimics the way node implements them. Both Shell
and FileSystem
now have a promises
property, which gives access to Promise based versions of methods in addition to the regular callback style methods. Method names are identical to their callback counterparts with the difference that instead of receiving a final argument as a callback, they return a Promise that is resolved or rejected based on the success of method execution.
See example below:
const fs = new Filer.FileSystem().promises;
fs.writeFile('/myfile', 'some data')
.then(() => fs.stat('/myfile'))
.then(stats => { console.log(`stats: ${JSON.stringify(stats)}`); })
.catch(err => { console.error(err); });
Filer.FileSystem(options, callback) constructor
File system constructor, invoked to open an existing file system or create a new one.
Accepts two arguments: an options
object, and an optional callback
. The options
object can specify a number of optional arguments, including:
name
: the name of the file system, defaults to '"local'
flags
: an Array of one or more flags to use when creating/opening the file system:
'FORMAT'
to force Filer to format (i.e., erase) the file system'NOCTIME'
to force Filer to not update ctime
on nodes when metadata changes (i.e., for better performance)'NOMTIME'
to force Filer to not update mtime
on nodes when data changes (i.e., for better performance)
provider
: an explicit storage provider to use for the file system's database context provider. See the section on Storage Providers.
The callback
function indicates when the file system is ready for use. Depending on the storage provider used, this might
be right away, or could take some time. The callback should expect two arguments: first, an error
argument, which will be
null if everything worked; second, an instance, such that you can access the newly ready FileSystem instance. Also users
should check the file system's readyState
and error
properties to make sure it is usable.
var fs;
function fsReady(err, fs) {
if(err) throw err;
}
fs = new Filer.FileSystem({
name: "my-filesystem",
flags: [ 'FORMAT' ],
provider: new Filer.FileSystem.providers.Memory()
}, fsReady);
NOTE: if the optional callback argument is not passed to the FileSystem
constructor,
operations done on the resulting file system will be queued and run in sequence when
it becomes ready.
Filer.FileSystem.providers - Storage Providers
Filer can be configured to use a number of different storage providers. The provider object encapsulates all aspects
of data access, making it possible to swap in different backend storage options. There are currently 4 different
providers to choose from:
FileSystem.providers.IndexedDB()
- uses IndexedDBFileSystem.providers.WebSQL()
- uses WebSQLFileSystem.providers.Fallback()
- attempts to use IndexedDB if possible, falling-back to WebSQL if necessaryFileSystem.providers.Memory()
- uses memory (not suitable for data that needs to survive the current session)
You can choose your provider when creating a FileSystem
:
var FileSystem = Filer.FileSystem;
var providers = FileSystem.providers;
var fs1 = new FileSystem();
var fs2 = new FileSystem({ provider: new providers.IndexedDB() });
var fs3 = new FileSystem({ provider: new providers.Fallback() });
Every provider has an isSupported()
method, which returns true
if the browser supports this provider:
if( Filer.FileSystem.providers.WebSQL.isSupported() ) {
}
You can also write your own provider if you need a different backend. See the code in src/providers
for details.
A number of other providers have been written, including:
Filer.Buffer
When reading and writing data, Filer follows node.js and uses Buffer
.
When in a node.js environment, native Buffer
s can be used, or Filer.Buffer, which is a shortcut
to node's Buffer
. In a browser, you can use also use Filer.Buffer
.
NOTE: a Filer.Buffer
in a browser is really an augmented Uint8Array
(i.e., the node Buffer
api
methods are added to the instance). See https://github.com/feross/buffer for more details.
NOTE: Filer.Buffer
currently includes the older, deprecated constructor functions, but these will be removed
at some point. You are encouraged to switch to use the newer class methods Buffer.from()
and Buffer.alloc()
. See the node.js Buffer docs.
new Buffer(array)
new Buffer(arrayBuffer[, byteOffset[, length]])
new Buffer(buffer)
new Buffer(string[, encoding])
new Buffer(size)
Buffer.from(array)
Buffer.from(arrayBuffer[, byteOffset[, length]])
Buffer.from(buffer)
Buffer.from(string[, encoding])
Buffer.alloc(size)
Buffer.allocUnsafe(size)
Filer.Path
The node.js path module is available via the Filer.Path
object. It is
identical to the node.js (see https://github.com/browserify/path-browserify) version with the following differences:
- The CWD always defaults to
/
- No support for Windows style paths
- Additional utility methods (see below)
var path = Filer.Path;
var dir = path.dirname('/foo/bar/baz/asdf/quux');
var base = path.basename('/foo/bar/baz/asdf/quux.html');
var ext = path.extname('index.html');
var newpath = path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
For more info see the docs in the path module for a particular method:
path.normalize(p)
- NOTE: Filer.Path.normalize does not add a trailing slashpath.join([path1], [path2], [...])
path.resolve([from ...], to)
path.relative(from, to)
path.dirname(p)
path.basename(p, [ext])
- NOTE: Filer.Path.basename will return '/'
vs. ''
path.extname(p)
path.sep
path.delimiter
Filer.Path also includes the following extra methods:
isNull(p)
returns true
or false
if the path contains a null character ('\u0000'
)addTrailing(p)
returns the path p
with a single trailing slash addedremoveTrailing(p)
returns the path p
with trailing slash(es) removed
Filer.Errors
The error objects used internally by Filer are also exposed via the Filer.Errors
object. As much as possible
these match their node.js counterparts, with a few Filer-specifc additions.
See src/errors.js for the complete
list. Errors can be used, or compared, like so:
Examples:
var err1 = new Filer.Errors.EEXIST();
var err2 = new Filer.Errors[47];
function callback(err) {
if(err instanceof Filer.Errors.EINVAL){
...
}
if(err.code === 'EINVAL') {
...
}
}
function callback(err) {
if(err.errno === 47){
...
}
console.log(err.message);
FileSystem Instance Methods
Once a FileSystem
is created, it has the following methods. NOTE: code examples below assume
a FileSystem
instance named fs
has been created like so:
var fs = new Filer.FileSystem();
- fs.rename(oldPath, newPath, callback)
- fs.ftruncate(fd, len, callback)
- fs.truncate(path, len, callback)
- fs.stat(path, callback)
- fs.fstat(fd, callback)
- fs.lstat(path, callback)
- fs.exists(path, callback)
- fs.link(srcpath, dstpath, callback)
- fs.symlink(srcpath, dstpath, [type], callback)
- fs.readlink(path, callback)
- fs.realpath(path, [cache], callback)
- fs.unlink(path, callback)
- fs.mknod(path, mode, callback)
- fs.rmdir(path, callback)
- fs.mkdir(path, [mode], callback)
- fs.access(path, [mode], callback)
- fs.mkdtemp(path, [options], callback)
- fs.readdir(path, callback)
- fs.close(fd, callback)
- fs.open(path, flags, [mode], callback)
- fs.utimes(path, atime, mtime, callback)
- fs.chown(path, uid, gid, callback)
- fs.fchown(fd, uid, gid, callback)
- fs.chmod(path, mode, callback)
- fs.fchmod(fd, mode, callback)
- fs.futimes(fd, atime, mtime, callback)
- fs.fsync(fd, callback)
- fs.write(fd, buffer, offset, length, position, callback)
- fs.read(fd, buffer, offset, length, position, callback)
- fs.readFile(filename, [options], callback)
- fs.writeFile(filename, data, [options], callback)
- fs.appendFile(filename, data, [options], callback)
- fs.setxattr(path, name, value, [flag], callback)
- fs.fsetxattr(fd, name, value, [flag], callback)
- fs.getxattr(path, name, callback)
- fs.fgetxattr(fd, name, callback)
- fs.removexattr(path, name, callback)
- fs.fremovexattr(fd, name, callback)
- fs.watch(filename, [options], [listener])
fs.rename(oldPath, newPath, callback)
Renames the file at oldPath
to newPath
. Asynchronous rename(2).
Callback gets no additional arguments.
Example:
fs.rename("/myfile.txt", "/myfile.bak", function(err) {
if(err) throw err;
});
fs.ftruncate(fd, len, callback)
Change the size of the file represented by the open file descriptor fd
to be length
len
bytes. Asynchronous ftruncate(2).
If the file is larger than len
, the extra bytes will be discarded; if smaller, its size will
be increased, and the extended area will appear as if it were zero-filled. See also fs.truncate().
Example:
var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error;
fs.write(fd, buffer, 0, buffer.length, 0, function(err, result) {
if(err) throw error;
fs.ftruncate(fd, 3, function(err) {
if(err) throw error;
fs.ftruncate(fd, 50, function(err) {
if(err) throw error;
fs.close(fd);
});
});
});
});
});
fs.truncate(path, len, callback)
Change the size of the file at path
to be length len
bytes. Asynchronous truncate(2). If the file is larger than len
, the extra bytes will be discarded; if smaller, its size will
be increased, and the extended area will appear as if it were zero-filled. See also fs.ftruncate().
Example:
var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error;
fs.write(fd, buffer, 0, buffer.length, 0, function(err, result) {
if(err) throw error;
fs.close(fd, function(err) {
if(err) throw error;
fs.truncate('/myfile', 3, function(err) {
if(err) throw error;
fs.truncate('/myfile', 50, function(err) {
if(err) throw error;
});
});
});
});
});
fs.stat(path, callback)
Obtain file status about the file at path
. Asynchronous stat(2).
Callback gets (error, stats)
, where stats
is an object with the following properties:
{
node: <string> // internal node id (unique)
dev: <string> // file system name
name: <string> // the entry's name (basename)
size: <number> // file size in bytes
nlinks: <number> // number of links
atime: <date> // last access time as JS Date Object
mtime: <date> // last modified time as JS Date Object
ctime: <date> // creation time as JS Date Object
atimeMs: <number> // last access time as Unix Timestamp
mtimeMs: <number> // last modified time as Unix Timestamp
ctimeMs: <number> // creation time as Unix Timestamp
type: <string> // file type (FILE, DIRECTORY, SYMLINK),
gid: <number> // group name
uid: <number> // owner name
mode: <number> // permissions
version: <number> // version of the node
}
The following convenience methods are also present on the callback's stats
:
isFile(): Returns true if the node is a file.
isDirectory(): Returns true if the node is a directory.
isBlockDevice(): Not implemented, returns false.
isCharacterDevice(): Not implemented, returns false.
isSymbolicLink(): Returns true if the node is a symbolic link.
isFIFO(): Not implemented, returns false.
isSocket(): Not implemented, returns false.
If the file at path
is a symbolic link, the file to which it links will be used instead.
To get the status of a symbolic link file, use fs.lstat() instead.
Examples:
function dirExists(path, callback) {
fs.stat(path, function(err, stats) {
if(err) return callback(err);
var exists = stats.type === "DIRECTORY";
callback(null, exists);
});
};
function fileSize(path, callback) {
fs.stat(path, function(err, stats) {
if(err) return callback(err);
var kb = stats.size / 1000;
callback(null, kb);
});
}
fs.fstat(fd, callback)
Obtain information about the open file known by the file descriptor fd
.
Asynchronous fstat(2).
Callback gets (error, stats)
. fstat()
is identical to stat()
, except that the file to be stat-ed is
specified by the open file descriptor fd
instead of a path. See also fs.stat
Example:
fs.open("/file.txt", "r", function(err, fd) {
if(err) throw err;
fs.fstat(fd, function(err, stats) {
if(err) throw err;
fs.close(fd);
});
});
fs.lstat(path, callback)
Obtain information about the file at path
(i.e., the symbolic link file itself) vs.
the destination file to which it links. Asynchronous lstat(2).
Callback gets (error, stats)
. See also fs.stat.
Example:
fs.link("/data/logs/august", "/data/logs/current", function(err) {
if(err) throw err;
fs.stat("/data/logs/current", function(err, stats) {
if(err) throw err;
var size = stats.size;
});
fs.lstat("/data/logs/current", function(err, stats) {
if(err) throw err;
var size = stats.size;
});
});
fs.exists(path, callback)
Test whether or not the given path exists by checking with the file system.
Then call the callback argument with either true or false.
Example:
fs.exists('/myfile', function (exists) {
console.log(exists ? "file exists" : "file not found");
});
fs.exists() is an anachronism and exists only for historical reasons. There should almost never be a reason to use it in your own code.
In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists() and fs.open(). Just open the file and handle the error when it's not there.
fs.link(srcPath, dstPath, callback)
Create a (hard) link to the file at srcPath
named dstPath
. Asynchronous link(2). Callback gets no additional arguments. Links are directory entries that point to the same file node.
Example:
fs.link('/logs/august.log', '/logs/current', function(err) {
if(err) throw err;
fs.readFile('/logs/current', 'utf8', function(err, data) {
var currentLog = data;
});
});
fs.symlink(srcPath, dstPath, [type], callback)
Create a symbolic link to the file at dstPath
containing the path srcPath
. Asynchronous symlink(2). Callback gets no additional arguments.
Symbolic links are files that point to other paths.
NOTE: Filer allows for, but ignores the optional type
parameter used in node.js.
The srcPath
may be a relative path, which will be resolved relative to dstPath
Example:
fs.symlink('/logs/august.log', '/logs/current', function(err) {
if(err) throw err;
fs.readFile('/logs/current', 'utf8', function(err, data) {
var currentLog = data;
});
});
fs.symlink('../file', '/dir/symlink', function(err) {
if(err) throw err;
});
fs.readlink(path, callback)
Reads the contents of a symbolic link. Asynchronous readlink(2).
Callback gets (error, linkContents)
, where linkContents
is a string
containing the symbolic link's link path. If the original srcPath
given
to symlink()
was a relative path, it will be fully resolved relative
to dstPath
when returned by readlink()
.
Example:
fs.symlink('/logs/august.log', '/logs/current', function(error) {
if(error) throw error;
fs.readlink('/logs/current', function(error, linkContents) {
});
});
fs.realpath(path, [cache], callback)
NOTE: Not implemented, see https://github.com/filerjs/filer/issues/85
fs.unlink(path, callback)
Removes the directory entry located at path
. Asynchronous unlink(2).
Callback gets no additional arguments. If path
names a symbolic link, the symbolic link will be removed
(i.e., not the linked file). Otherwise, the filed named by path
will be removed (i.e., deleted).
Example:
fs.unlink('/backup.old', function(err) {
if(err) throw err;
});
fs.mknod(path, mode, callback)
Creates a node at path
based on the mode passed which is either FILE
or DIRECTORY
. Asynchronous mknod(2). Callback gets no additional arguments.
Example:
fs.mknod('/dir', 'DIRECTORY', function(err) {
if(err) throw err;
fs.mknod('/dir/myfile', 'FILE', function(err) {
if(err) throw err;
});
});
fs.rmdir(path, callback)
Removes the directory at path
. Asynchronous rmdir(2).
Callback gets no additional arguments. The operation will fail if the directory at path
is not empty.
Example:
fs.unlink('/docs/a.txt', function(err) {
if(err) throw err;
fs.rmdir('/docs', function(err) {
if(err) throw err;
});
});
fs.mkdir(path, [mode], callback)
Makes a directory with name supplied in path
argument. Asynchronous mkdir(2). Callback gets no additional arguments.
NOTE: Filer allows for, but ignores the optional mode
argument used in node.js.
Example:
fs.mkdir('/home', function(err) {
if(err) throw err;
fs.mkdir('/home/carl', function(err) {
if(err) throw err;
});
});
fs.access(path, [mode], callback)
Tests a user's permissions for the file or directory supplied in path
argument. Asynchronous access(2). Callback gets no additional arguments. The mode
argument can be one of the following (constants are available on fs.constants
):
F_OK
: Test for existence of file.R_OK
: Test whether the file exists and grants read permission.W_OK
: Test whether the file exists and grants write permission.X_OK
: Test whether the file exists and grants execute permission.
NOTE: you can also create a mask consisting of the bitwise OR of two or more values (e.g. fs.constants.W_OK | fs.constants.R_OK
).
Example:
fs.access(file, fs.constants.F_OK, function(err) {
console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
});
fs.mkdtemp(prefix, options, callback)
Makes a temporary directory with prefix supplied in path
argument. Method will append six random characters directly to the prefix. Asynchronous. Callback gets (error, path)
, where path is the path to the created directory.
NOTE: Filer allows for, but ignores the optional options
argument used in node.js.
Example:
fs.mkdtemp("/foo-", function (error, path) {
});
fs.mkdtemp("/myDir/tmp", function (error, path) {
});
fs.readdir(path, callback)
Reads the contents of a directory. Asynchronous readdir(3).
Callback gets (error, files)
, where files
is an array containing the names of each directory entry (i.e., file, directory, link) in the directory, excluding .
and ..
.
Example:
fs.readdir('/docs', function(err, files) {
if(err) throw err;
});
fs.close(fd, callback)
Closes a file descriptor. Asynchronous close(2).
Callback gets no additional arguments.
Example:
fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error;
fs.close(fd);
});
fs.open(path, flags, [mode], callback)
Opens a file. Asynchronous open(2).
Callback gets (error, fd)
, where fd
is the file descriptor. The flags
argument can be:
'r'
: Open file for reading. An exception occurs if the file does not exist.'r+'
: Open file for reading and writing. An exception occurs if the file does not exist.'w'
: Open file for writing. The file is created (if it does not exist) or truncated (if it exists).'w+'
: Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).'a'
: Open file for appending. The file is created if it does not exist.'a+'
: Open file for reading and appending. The file is created if it does not exist.
NOTE: Filer allows for, but ignores the optional mode
argument used in node.js.
Example:
fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error;
fs.close(fd);
});
fs.utimes(path, atime, mtime, callback)
Changes the file timestamps for the file given at path path
. Asynchronous utimes(2). Callback gets no additional arguments. Both atime
(access time) and mtime
(modified time) arguments should be a JavaScript Date or Number.
Example:
var now = Date.now();
fs.utimes('/myfile.txt', now, now, function(err) {
if(err) throw err;
});
fs.futimes(fd, atime, mtime, callback)
Changes the file timestamps for the open file represented by the file descriptor fd
. Asynchronous utimes(2). Callback gets no additional arguments. Both atime
(access time) and mtime
(modified time) arguments should be a JavaScript Date or Number.
Example:
fs.open('/myfile.txt', function(err, fd) {
if(err) throw err;
var now = Date.now();
fs.futimes(fd, now, now, function(err) {
if(err) throw err;
fs.close(fd);
});
});
fs.chown(path, uid, gid, callback)
Changes the owner and group of a file. Asynchronous chown(2). Callback gets no additional arguments. Both uid
(user id) and gid
(group id) arguments should be a JavaScript Number. By default, 0x0
is used (i.e., root:root
ownership).
Example:
fs.chown('/myfile.txt', 500, 500, function(err) {
if(err) throw err;
});
fs.fchown(fd, uid, gid, callback)
Changes the owner and group of a file. Asynchronous chown(2). Callback gets no additional arguments. Both uid
(user id) and gid
(group id) arguments should be a JavaScript Number. By default, 0x0
is used (i.e., root:root
ownership).
Example:
fs.open('/myfile.txt', function(err, fd) {
if(err) throw err;
fs.fchown(fd, 500, 500, function(err) {
if(err) throw err;
fs.close(fd);
});
});
fs.chmod(path, mode, callback)
Changes the mode of a file. Asynchronous chmod(2). Callback gets no additional arguments. The mode
argument should be a JavaScript Number, which combines file type and permission information. Here are a list of common values useful for setting the mode
:
-
File type S_IFREG=0x8000
-
Dir type S_IFDIR=0x4000
-
Link type S_IFLNK=0xA000
-
Permissions 755=0x1ED
-
Permissions 644=0x1A4
-
Permissions 777=0x1FF
-
Permissions 666=0x1B6
By default, directories use (0x4000 | 0x1ED)
and files use (0x8000 | 0x1A4)
.
Example:
var mode = 0x8000 | 0x1FF
fs.chmod('/myfile.txt', mode, function(err) {
if(err) throw err;
});
fs.fchmod(fd, mode, callback)
Changes the mode of a file. Asynchronous chmod(2). Callback gets no additional arguments. The mode
argument should be a JavaScript Number, which combines file type and permission information. By default, 755
(dir) and 644
(file) are used.
Example:
fs.open('/myfile.txt', function(err, fd) {
if(err) throw err;
var mode = 0x8000 | 0x1FF
fs.fchmod(fd, mode, function(err) {
if(err) throw err;
fs.close(fd);
});
});
fs.fsync(fd, callback)
Synchronize the data and metadata for the file referred to by fd
to disk.
Asynchronous fsync(2).
The callback gets (error)
.
fs.open('/myfile', 'r', function(error, fd) {
if(err) throw err;
fs.fsync(fd, function(error) {
if(err) throw err;
fs.close(fd, done);
});
});
fs.write(fd, buffer, offset, length, position, callback)
Writes bytes from buffer
to the file specified by fd
. Asynchronous write(2), pwrite(2). The offset
and length
arguments describe the part of the buffer to be written. The position
refers to the offset from the beginning of the file where this data should be written. If position
is null
, the data will be written at the current position. The callback gets (error, nbytes)
, where nbytes
is the number of bytes written.
NOTE: Filer currently writes the entire buffer in a single operation. However, future versions may do it in chunks.
Example:
var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error;
var expected = buffer.length, written = 0;
function writeBytes(offset, position, length) {
length = length || buffer.length - written;
fs.write(fd, buffer, offset, length, position, function(err, nbytes) {
if(err) throw error;
written += nbytes;
if(written < expected)
writeBytes(written, null);
else
fs.close(fd);
});
}
writeBytes(0, 0);
});
fs.read(fd, buffer, offset, length, position, callback)
Read bytes from the file specified by fd
into buffer
. Asynchronous read(2), pread(2). The offset
and length
arguments describe the part of the buffer to be used. The position
refers to the offset from the beginning of the file where this data should be read. If position
is null
, the data will be written at the current position. The callback gets (error, nbytes)
, where nbytes
is the number of bytes read.
NOTE: Filer currently reads into the buffer in a single operation. However, future versions may do it in chunks.
Example:
fs.open('/myfile', 'r', function(err, fd) {
if(err) throw err;
fs.fstat(fd, function(err, stats) {
if(err) throw err;
var nbytes = expected = stats.size;
var buffer = Filer.Buffer.alloc(nbytes);
var read = 0;
function readBytes(offset, position, length) {
length = length || buffer.length - read;
fs.read(fd, buffer, offset, length, position, function(err, nbytes) {
if(err) throw err;
read += nbytes;
if(read < expected)
readBytes(read, null);
else
fs.close(fd);
});
}
readBytes(0, 0);
});
});
fs.readFile(filename, [options], callback)
Reads the entire contents of a file. The options
argument is optional, and can take the form "utf8"
(i.e., an encoding) or be an object literal: { encoding: "utf8", flag: "r" }
. If no encoding is specified, the raw binary buffer is returned via the callback. The callback gets (error, data)
, where data is the contents of the file.
Examples:
fs.readFile('/myfile.txt', 'utf8', function (err, data) {
if (err) throw err;
});
fs.readFile('/myfile.txt', function (err, data) {
if (err) throw err;
});
fs.writeFile(filename, data, [options], callback)
Writes data to a file. data
can be a string or Buffer
, in which case any encoding option is ignored. The options
argument is optional, and can take the form "utf8"
(i.e., an encoding) or be an object literal: { encoding: "utf8", flag: "w" }
. If no encoding is specified, and data
is a string, the encoding defaults to 'utf8'
. The callback gets (error)
.
Examples:
fs.writeFile('/myfile.txt', "...data...", function (err) {
if (err) throw err;
});
var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.writeFile('/myfile', buffer, function (err) {
if (err) throw err;
});
fs.appendFile(filename, data, [options], callback)
Writes data to the end of a file. data
can be a string or a Buffer
, in which case any encoding option is ignored. The options
argument is optional, and can take the form "utf8"
(i.e., an encoding) or be an object literal: { encoding: "utf8", flag: "w" }
. If no encoding is specified, and data
is a string, the encoding defaults to 'utf8'
. The callback gets (error)
.
Examples:
fs.writeFile('/myfile.txt', "More...", function (err) {
if (err) throw err;
});
fs.appendFile('/myfile.txt', "Data...", function (err) {
if (err) throw err;
});
var data = Filer.Buffer.from([1, 2, 3, 4]);
var more = Filer.Buffer.from([5, 6, 7, 8]);
fs.writeFile('/myfile', data, function (err) {
if (err) throw err;
fs.appendFile('/myfile', more, function (err) {
if (err) throw err;
});
});
fs.setxattr(path, name, value, [flag], callback)
Sets an extended attribute of a file or directory named path
. Asynchronous setxattr(2).
The optional flag
parameter can be set to the following:
XATTR_CREATE
: ensures that the extended attribute with the given name will be new and not previously set. If an attribute with the given name already exists, it will return an EExists
error to the callback.XATTR_REPLACE
: ensures that an extended attribute with the given name already exists. If an attribute with the given name does not exist, it will return an ENoAttr
error to the callback.
Callback gets no additional arguments.
Example:
fs.writeFile('/myfile', 'data', function(err) {
if(err) throw err;
fs.setxattr('/myfile', 'extra', 'some-information', function(err) {
if(err) throw err;
});
fs.setxattr('/myfile', 'extra-complex', { key1: 'value1', key2: 103 }, function(err) {
if(err) throw err;
});
});
fs.fsetxattr(fd, name, value, [flag], callback)
Sets an extended attribute of the file represented by the open file descriptor fd
. Asynchronous setxattr(2). See fs.setxattr
for more details. Callback gets no additional arguments.
Example:
fs.open('/myfile', 'w', function(err, fd) {
if(err) throw err;
fs.fsetxattr(fd, 'extra', 'some-information', function(err) {
if(err) throw err;
});
fs.fsetxattr(fd, 'extra-complex', { key1: 'value1', key2: 103 }, function(err) {
if(err) throw err;
});
fs.close(fd);
});
fs.getxattr(path, name, callback)
Gets an extended attribute value for a file or directory. Asynchronous getxattr(2).
Callback gets (error, value)
, where value
is the value for the extended attribute named name
.
Example:
fs.getxattr('/myfile', 'extra', function(err, value) {
if(err) throw err;
});
fs.fgetxattr(fd, name, callback)
Gets an extended attribute value for the file represented by the open file descriptor fd
.
Asynchronous getxattr(2).
See fs.getxattr
for more details. Callback gets (error, value)
, where value
is the value for the extended attribute named name
.
Example:
fs.open('/myfile', 'r', function(err, fd) {
if(err) throw err;
fs.fgetxattr(fd, 'extra', function(err, value) {
if(err) throw err;
});
fs.close(fd);
});
fs.removexattr(path, name, callback)
Removes the extended attribute identified by name
for the file given at path
. Asynchronous removexattr(2). Callback gets no additional arguments.
Example:
fs.removexattr('/myfile', 'extra', function(err) {
if(err) throw err;
});
fs.fremovexattr(fd, name, callback)
Removes the extended attribute identified by name
for the file represented by the open file descriptor fd
.
Asynchronous removexattr(2). See fs.removexattr
for more details.
Callback gets no additional arguments.
Example:
fs.open('/myfile', 'r', function(err, fd) {
if(err) throw err;
fs.fremovexattr(fd, 'extra', function(err) {
if(err) throw err;
});
fs.close(fd);
});
fs.watch(filename, [options], [listener])
Watch for changes to a file or directory at filename
. The object returned is an FSWatcher
,
which is an EventEmitter
with the following additional method:
close()
- stops listening for changes, and removes all listeners from this instance. Use this
to stop watching a file or directory after calling fs.watch()
.
The only supported option is recursive
, which if true
will cause a watch to be placed
on a directory, and all sub-directories and files beneath it.
The listener
callback gets two arguments (event, filename)
. event
is either 'rename'
or 'change'
,
(currenty only 'rename'
is supported) and filename
is the name of the file/dir which triggered the event.
Unlike node.js, all watch events return a path. Also, all returned paths are absolute from the root
vs. just a relative filename.
Examples:
var watcher = fs.watch('/myfile', function(event, filename) {
watcher.close();
});
fs.writeFile('/myfile', 'data');
var watcher = fs.watch('/myfile2');
watcher.on('change', function(event, filename) {
watcher.close();
});
fs.writeFile('/myfile2', 'data2');
var watcher = fs.watch('/data', { recursive: true }, function(event, filename) {
watcher.close();
});
fs.writeFile('/data/subdir/file', 'data');
FileSystemShell
Many common file system shell operations are available by using a FileSystemShell
object.
The FileSystemShell
is used in conjunction with a FileSystem
,
and provides augmented features. Many separate FileSystemShell
objects can exist per
FileSystem
, but each FileSystemShell
is bound to a single instance of a FileSystem
for its lifetime.
A FileSystemShell
is created by instantiating Filer.FileSystem().Shell
:
var fs = new Filer.FileSystem();
var sh = new fs.Shell(options);
var sh2 = new fs.Shell(options);
In addition, the constructor function can be accessed through Filer
:
var fs = new Filer.FileSystem();
var sh = new fs.Shell();
Filer.Shell.prototype.newFunction = ...;
sh.newFunction();
The FileSystemShell
can take an optional options
object. The options
object
can include env
, which is a set of environment variables. Currently supported variables
include TMP
(the path to the temporary directory), and PATH
(the list of known paths) and
others may be added in the future. You can also add your own, or update existing variables.
var fs = new Filer.FileSystem();
var sh = new fs.Shell({
env: {
TMP: '/tempdir',
PATH: '/one:/two'
}
});
var tempPath = sh.env.get('TMP');
sh.env.set('TMP', '/newtempdir');
NOTE: unless otherwise stated, all FileSystemShell
methods can take relative or absolute
paths. Relative paths are resolved relative to the shell's current working directory (sh.cwd
).
This is different from the FileSystem
, which requires absolute paths, and has no notion
of a current working directory.
FileSystemShell Properties
A FileSystemShell
has a number of properties, including:
fs
- (readonly) a reference to the bound FileSystem
env
- (readonly) the shell's environment. The shell's environemnt env
object has get(name)
and set(name, value)
methods.
Example:
var fs = new Filer.FileSystem();
var sh = new fs.Shell();
var p = sh.env.get('PATH');
var before = sh.pwd();
var after;
sh.cd('/newdir', function(err) {
if(err) throw err;
after = sh.pwd();
});
FileSystemShell Instance Methods
Once a FileSystemShell
object is created, it has the following methods. NOTE: code
examples below assume a FileSystemShell
instance named sh
has been created like so:
var fs = new Filer.FileSystem();
var sh = new fs.Shell();
- sh.cd(path, callback)
- sh.pwd()
- sh.find(dir, [options], callback)
- sh.ls(dir, [options], callback)
- sh.exec(path, [args], callback)
- sh.touch(path, [options], callback)
- sh.cat(files, callback)
- sh.rm(path, [options], callback)
- sh.tempDir(callback)
- sh.mkdirp(path, callback)
sh.cd(path, callback)
Changes the current working directory to the directory at path
. The callback returns
an error if path
does not exist, or is not a directory. Once the callback occurs
the shell's cwd is updated to the new path (you can access it via sh.pwd()
).
Example:
sh.cd('/dir1', function(err) {
if(err) throw err;
});
sh.pwd()
Returns the shell's current working directory. See sh.cd().
sh.find(dir, [options], callback)
Recursively walk a directory tree, reporting back all paths that were
found along the way. Asynchronous find(1)
If given no options, find
walks the given dir path
and the callback gives function(err, found)
, where found
is an array of
all paths discovered during a depth-first walk.
Valid options include a regex
for pattern matching paths, allowing paths
to be ignored (e.g., regex: /\.bak$/
to find all .bak
files). You can
also use name
and path
to provide a match pattern for the basename and
dirname respectively (e.g., {name: '*.js'}
to find all JavaScript files or
{path: '*-modules'}
to only look in folders named base-modules
, foo-modules
, etc.).
Finally, you can also provide an exec
function of the form function(path, next)
where
path
is the current path that was found and matches any provided regex
(NOTE: dir paths have an '/' appended), and next
is a callback to call
when you are done processing the path.
Example:
function processPath(path, next) {
if(path.endsWith('/')) {
console.log('Found dir: ' + path);
} else {
console.log('Found file: ' + path);
}
next();
}
sh.find('/', {exec: processPath}, function(err, found) {
});
sh.find('/data', {regex: /map20\d\.jpg$/, exec: processPath}, function(err) {
});
sh.find('/app/user', {
name: '*.bak',
exec: function(path, next) {
sh.rm(path, next);
}
}, function callback(err, found) {
if(err) throw err;
if(found.length) {
console.log('Deleted the following ' + found.length + ' files: ', found);
}
});
sh.ls(dir, [options], callback)
Get the listing of a directory, returning an array of directory entries
in the same form as fs.stat(), with the exception that a new Array named
contents
is added for directory entries, containing child entries.
By default sh.ls()
gives a shallow listing. If you want to follow
directories as they are encountered, use the recursive=true
option. NOTE:
you should not count on the order of the returned entries always being the same.
Example:
sh.ls('/dir', function(err, entries) {
if(err) throw err;
});
sh.ls('/dir', { recursive: true }, function(err, entries) {
if(err) throw err;
});
sh.exec(path, [args], callback)
Attempts to execute the .js command located at path
. The sh.exec
method
enables apps to install larger programs into the file system and run them
later without having to re-download. Such commands should be written so as
to assume the existence of 3 global variables, which will be defined at runtime:
fs
- [FileSystem] the FileSystem
object bound to this shell.args
- [Array] a list of any arguments for the command, or the empty listcallback
- [Function] a callback function of the form function callback(error, result)
to call when done.
The .js command's contents should be the body of a function that
looks like this:
function(fs, args, callback) {
}
Example:
var cmd = "fs.unlink(args[0], callback);"
fs.writeFile('/cmd.js', cmd, callback(err) {
if(err) throw err;
sh.exec('/cmd.js', [ '/file' ], function(err, result) {
if(err) throw err;
});
});
sh.touch(path, [options], callback)
Create a file if it does not exist, or update the access and modified
times if it does. Valid options include:
updateOnly
- true
if the file's access/modified dates are to be updated
only (but missing file not to be)date
- a date to use instead of the current date and time when updating
access and modified dates.
Example:
sh.touch('/newfile', function(err) {
if(err) throw err;
fs.exists('/newfile', function(exists) {
}
});
sh.cat(files, callback)
Concatenates multiple files into a single string, with each file
separated by a newline character. The files
argument should be
a String (i.e., path to a single file) or an Array of Strings (i.e.,
multiple paths for multiple files).
Example:
sh.cat([ './file1', '../file2' ], function(err, data) {
if(err) throw err;
});
sh.rm(path, [options], callback)
Removes (deletes) the file or directory at path
. If path
is a file, it will
be removed. If path
is a directory, it will be removed if it is empty, otherwise
the callback will receive an error. In order to remove non-empty directories,
use the recursive=true
option.
Example:
sh.rm('./file', function(err) {
if(err) throw err;
});
sh.rm('/dir', { recursive: true }, function(err) {
if(err) throw err;
});
sh.tempDir(callback)
Gets the path to the shell's temporary directory, creating it if it
does not already exist. The temp directory to use is specified in the
env.TMP
environment variable. The callback receives an error
and the tempDir
path. NOTE: it is safe to call this many times (i.e.,
the temp dir will only be created once). No effort is made to clean-up
the temp dir, and it is up to the caller to destroy it if desired.
Example:
sh.tempDir(function(err, tmp) {
if(err) throw err;
});
sh.env.TMP = '/temporary'
sh.tempDir(function(err, tmp) {
if(err) throw err;
});
sh.mkdirp(path, callback)
Recursively creates the directory at the provided path. If the
directory already exists, no error is returned. All parents must
be valid directories (not files).
Example:
sh.mkdirp('/test/mkdirp', function(err) {
if(err) throw err;
});