A new and improved API for asynchronous file I/O now exists and should be used instead of OS.File wherever possible. Please see the full IOUtils API.
This page details how to use File I/O from the main thread. For other uses of OS.File, please see the corresponding page.
To import OS.File into your chrome code, add the following line at the start of your script:
Components.utils.import("resource://gre/modules/osfile.jsm")
Before using OS.File from the main thread, you need some understanding of the Promise library.
See the Promise
object documentation for details.
Also, OS.File plays very nicely with Task.jsm.
The following snippet opens a file "file.txt" and read its contents as a string, using the default encoding (utf-8).
The content is read asynchronously. The result is a Promise.
let decoder = new TextDecoder(); // This decoder can be reused for several reads let promise = OS.File.read("file.txt"); // Read the complete file as an array promise = promise.then( function onSuccess(array) { return decoder.decode(array); // Convert this array to a text } );
This example requires Firefox 18 or a more recent version.
The following snippet writes the text "This is some text" to a string "file.txt", using the default encoding (utf-8). It uses an atomic write to ensure that the file is not modified if, for some reason, the write cannot complete (typically because the computer is turned off, the battery runs out, or the application is stopped.)
let encoder = new TextEncoder(); // This encoder can be reused for several writes let array = encoder.encode("This is some text"); // Convert the text to an array let promise = OS.File.writeAtomic("file.txt", array, // Write the array atomically to "file.txt", using as temporary {tmpPath: "file.txt.tmp"}); // buffer "file.txt.tmp".
The following variant does the same thing but will fail if "file.txt" already exists:
let encoder = new TextEncoder(); // This encoder can be reused for several writes let array = encoder.encode("This is some text"); // Convert the text to an array let promise = OS.File.writeAtomic("file.txt", array, // Write the array atomically to "file.txt", using as temporary {tmpPath: "file.txt.tmp", noOverwrite: true}); // buffer "file.txt.tmp".
These examples require Firefox 19 or a more recent version.
You have to use OS.File.move
to rename a file:
let promise = OS.File.move("oldname.txt", "newname.txt", {noOverwrite:true});
Here's a working example which renames test.txt
to testRenamed.txt
if the file is located in directory C:\Jean\
var promise = OS.File.move(OS.Path.join('C:', 'Jean', 'test.txt'), OS.Path.join('C:', 'Jean', 'testRenamed.txt')); promise.then( function() { console.log('rename successful') }, function(aRejectReason) { console.log('rename failed, aRejectReason = ', aRejectReason) } )
The noOverwrite true is important, as default is false which means if a file in the directory exists already with the same name it will no longer be there after this "rename" operation, which is a "move".
The following snippet copies file "oldname.txt" to "newname.txt". On most operating systems, this operation is handled directly by the operating system itself, which makes it as fast as possible.
let promise = OS.File.copy("oldname.txt", "newname.txt");
This example requires Firefox 16 or a more recent version.
The following snippet obtains the path to file "sessionstore.js", contained in the user's profile directory.
let sessionstore = OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"); // Under Linux, this is generally "$HOME/.firefox/Profiles/$PROFILENAME/sessionstore.js" // Under MacOS, this is generally "$HOME/Library/Application Support/Firefox/$PROFILENAME/sessionstore.js" // Under Windows, this is generally "%APPDATA%\Local\temp\%PROFILENAME%"\sessionstore.js // etc.
The following snippet determines if some path represents a file or a directory:
let promise = OS.File.stat(somePath); promise = promise.then( function onSuccess(stat) { if (stat.isDir) { // The path represents a directory } else { // The path represents a file, not a directory } }, function onFailure(reason) { if (reason instanceof OS.File.Error && reason.becauseNoSuchFile) { // The file does not exist } else { // Some other error throw reason; } } );
The following snippet writes a (presumably large) buffer by chunks. Note that this snippet is useful as a demonstration of complex asynchronous programming with OS.File – in most cases, function OS.File.writeAtomic
is a better choice.
let writeStream = function writeStream(data, outFile, chunkSize) { let view = new Uint8Array(data); let loop = function loop(pos) { // Define a recursive asynchronous loop. if (pos <= view.byteLength) { // Note: Should this be pos >= view.byteLength ? return Promise.resolve(true); // Loop end. } let promise = file.write(view.subarray(pos, chunkSize)); // Write a subset of |data| return promise.then(function onSuccess(bytes) { return loop(pos + bytes); // ... and loop. }); }; let promise = loop(0); // Enter the loop. promise = promise.then(function onSuccess() { // Once loop is complete, finalize. file.close(); }, function onError(reason) { file.close(); throw reason; }); return promise; }
Or a variant using Task.js (or at least the subset already present on mozilla-central):
let writeStream = function writeStream(data, outFile, chunkSize) { return Task.spawn(function() { let view = new Uint8Array(data); let pos = 0; while (pos < view.byteLength) { pos += yield outFile.write(view.subarray(pos, chunkSize)); } outFile.close(); }).then( null, function onFailure(reason) { outFile.close(); throw reason; } ); }
This exmaple uses Image
to load an image from a path (note: if your path is a file on disk you must use local file; this is accomplished with OS.Path.toFileURI
, which accepts a string). After image loads it then draws it to canvas
, makes it a blob
, and uses FileReader
to turn it into ArrayBuffer(View)
, then uses OS.File.writeAtomic to save to disk.
var img = new Image();
img.onload = function() {
var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
(canvas.toBlobHD || canvas.toBlob).call(canvas, function(b) {
var r = Cc['@mozilla.org/files/filereader;1'].createInstance(Ci.nsIDOMFileReader);
//new FileReader();
r.onloadend = function() {
// r.result contains the ArrayBuffer.
var writePath = OS.Path.join(OS.Constants.Path.desktopDir, 'savedImage.png');
var promise = OS.File.writeAtomic(writePath, new Uint8Array(r.result), { tmpPath: writePath + '.tmp' });
promise.then(
function(aVal) {
console.log('successfully saved image to disk');
},
function(aReason) {
console.log('writeAtomic failed for reason:', aReason);
}
);
};
r.readAsArrayBuffer(b);
}, 'image/png');
};
//var path = OS.Path.toFileURI(OS.Path.join(OS.Contants.Path.desktopDir, 'my.png')); //do it like this for images on disk
var path = 'https://mozorg.cdn.mozilla.net/media/img/firefox/channel/toggler-beta.png?2013-06'; //do like this for images online
img.src = path;
This example shows how to use open
, write
, and close
to append to a file. If the file does not exist, it is created. At the time of this writing, write
does not support encoding
option so the text to be written has to be encoded with TextEncoder
. This example also shows the resolve value of open (an instance of OS.File, this is a file, so you can do any of the methods on it found here), write
(a number indicating bytes written), and close
(undefined
, meaning there is no resolve value).
var pth = OS.Path.join(OS.Constants.Path.desktopDir, 'app.txt'); OS.File.open(pth, {write: true, append: true}).then(valOpen => { console.log('valOpen:', valOpen); var txtToAppend = '
append some text\n'; var txtEncoded = new TextEncoder().encode(txtToAppend); valOpen.write(txtEncoded).then(valWrite => { console.log('valWrite:', valWrite); valOpen.close().then(valClose => { console.log('valClose:', valClose); console.log('successfully appended'); }); }); });
Promise<File> open(in string path, [optional] in object mode, [optional] in object options); |
Promise<object> openUnique(in string path, [optional] in object options); |
Promise<void> copy(in string sourcePath, in string destPath, [optional] in object options); |
Promise<bool> exists(in string path); |
Promise<string> getCurrentDirectory(); |
Promise<void> makeDir(in string path, [optional] in object options); |
Promise<void> move(in string sourcePath, in string destPath); |
Promise<Uint8Array> read(in string path, [optional] in object options); |
Promise<void> remove(in string path, [optional] in object options); |
Promise<void> removeEmptyDir(in string path, [optional] in object options); |
Promise<void> removeDir(in string path, [optional] in object options); |
Promise<void> setCurrentDirectory(in string path); |
Promise<void> setDates(in string path, in Date|number accessDate, in Date|number modificationDate); |
Promise<void> setPermissions(in string path, in object options ); |
Promise<File.Info> stat(in string path, [optional] in object options); |
Promise<void> unixSymLink(in string targetPath, in string createPath); |
Promise<void> writeAtomic(in string path, in ArrayView data, in object options); |
Use method OS.File.open()
to open a file.
Promise<File> open( in string path, [optional] in object mode, [optional] in object options )
path
mode
Optionalread
true
, the file will be opened for reading. Depending on other fields, it may also be opened for writing.write
true
, the file will be opened for writing. Depending on other fields, it may also be opened for reading.Prior to Gecko 27, unless create
or truncate
are set or explicit unixFlags
are given, the file will be opened for appending on Unix/Linux. However, the file is not opened for appending on Windows. See bug 924858. Starting with Gecko 27, you may use the append
flag instead. For an example using append see here.
truncate
| trunc
true
, the file will be opened for writing. If the file does not exist, it will be created. If the file exists, its contents will be removed. Cannot be used with create
.create
true
, file will be opened for writing. The file must not exist. If the file already exists, throw an error. Cannot be used with truncate
or existing
.existing
true
, the file must already exist. If the file does not exist, throw an error. Cannot be used with create
.append
true
, the file will be opened for appending, meaning the equivalent of .setPosition(0, POS_END)
is executed before each write. The default is true
, i.e. opening a file for appending. Specify append: false
to open the file in regular mode.options
OptionalunixFlags
open
. If unspecified, build these flags from the contents of mode
. You can build these flags from values OS.Constants.libc.O_*.unixMode
open
. If unspecified, files are created with a default mode of 0600 (file is private to the user, the user can read and write). You can build this mode from values OS.Constants.libc.S_I*
.winShare
CreateFile
. If unspecified, files are opened with a default sharing policy (file is not protected against being read/written/removed by another process or another use in the same process). You can build this policy from constants OS.Constants.Win.FILE_SHARE_*.winSecurity
CreateFile
. If unspecified, no security attributes.winAccess
CreateFile
. This also requires option winDisposition
and this replaces argument mode
. If unspecified, value is built from mode
.winDisposition
CreateFile
. This also requires option winAccess
and this replaces argument mode
. If unspecified, value is built from mode
.An instance of OS.File
representing the expected file.
Note that the operating system limits the number of files that can be opened simultaneously by one process, so do not forget to close
that file once you have finished it, to ensure that you are not blocking the rest of the process.
When opening files for writing, they will be opened for appending unless you specify append: false
in Gecko 27 and later. In Gecko 26 and earlier, on platforms other than Windows, the files will be opened for appending unless you specify explicit unixFlags
or open the file with either create
or truncate
flags. In Gecko 26 and earlier on Windows, files will never be opened for appending.
To open an existing file for writing without appending in a compatible way on all platforms in both Gecko 27 and later and Gecko 26 and earlier, you should specify both the append
flag and unixFlags
.
// Open a file for writing without appending to it. Task.spawn(function() { // Under Unix, you'll have to specify your own unixFlags for Gecko < 27 to avoid append mode. var options = {}; if (OS.Constants.libc) { // Own flags omitting O_APPEND, e.g. options.unixFlags = OS.Constants.libc.O_CREAT | OS.Constants.libc.O_WRONLY; } // For Gecko >= 27, it is enough, but crucial, to set the correct append flag. var outfile = yield OS.File.open("file.tmp", {write: true, append: false}, options); try { // ... do something with that file } finally { yield outfile.close(); } });
This uses Tasks.jsm to open a file and keep it open. When you are done with it, like in shutdown of restartless add-on, you should close the file so it becomes editable again.
let options = { winShare: 0 // Exclusive lock on Windows }; if (OS.Constants.libc.O_EXLOCK) { // Exclusive lock on *nix options.unixFlags = OS.Constants.libc.O_EXLOCK; } let file = yield OS.File.open(..., options);
Then when you want to unlock the file so it can be edited from other places, close the file.
file.close();
This example is from Stackoverflow: OS.File check last modified date before OS.read
Creates and opens a file with a unique name. By default, generate a random hex number and use it to create a unique new file name.
Promise<object> openUnique( in string path, [optional] in object options ) throws OS.File.Error
path
options
OptionalhumanReadable
true
, create a new filename appending a decimal number, e.g., filename-1.ext, filename-2.ext. If false
use hex numbers, e.g., filename-A65BC0.ext.maxAttempts
An object contains a file object{file} and the path{path}.
OS.File.Error
Copy a file.
void copy( in string sourcePath, in string destPath [optional] in object options) throws OS.File.Error
sourcePath
destPath
options
OptionalnoOverwrite
destPath
already exists, do not overwrite it, but rather launch an exception.OS.File.Error
Performance notes
noOverwrite
than to check manually whether the file exists.copyfile
), Linux/Android (native operation splice
), and Windows (native operation CopyFile
).Determine whether a file exists
Promise<bool> exists( in string path )
path
true if the file exists, false otherwise
Performance note: For the sake of performance, you should avoid this function whenever possible. For instance, rather than calling exists() to determine if a directory should be created with makeDir, you should rather create the directory with makeDir and catch the error if the directory exists. This will ensure that you only need to perform one I/O operation rather than two.
Return the current directory
Promise<string> getCurrentDirectory()
The path to the current directory.
Safety note: Recall that the current directory can change during the execution of the process. Therefore, the information returned by this function may be false by the time you receive it.
Create a new directory
Promise<void> makeDir( in string path, [optional] in object options ) throws OS.File.Error
path
options
OptionalignoreExisting
true
, succeed even if the directory already exists (default behavior). Otherwise, fail if the directory already exists. NOTE: If from
is specified then even if ignoreExisting
is specified as false
, it will not fail due to pre-existence of directories, because the from
option tells makeDir
to make the folders if not found.unixMode
OS.Constants.libc.S_I*
.winSecurity
CreateDirectory
. If unspecified, no security attributes.from
makeDir
creates all the ancestors of path
that are descendents of from
. Note that from
and its existing descendents must be user-writeable and that path
must be a descendent of from
.Move a file.
Promise<void> move( in string sourcePath, in string destPath [optional] in object options )
sourcePath
sourcePath
is a directory.destPath
destPath
is a directory.options
OptionalnoOverwrite
destPath
already exists, do not overwrite it, but rather launch an exception.noCopy
OS.File.Error
Performance note: This operation is OS-optimized under OS X, Linux/Android, and Windows.
Read the contents of a file
Promise<Uint8Array> read( in string path, [optional] in number bytes )
path
bytes
OptionalAn array holding bytes bytes (or less if the file did not contain as many bytes).
OS.File.Error
As of Firefox 30, OS.File.read()
takes an options object as second argument.
Promise<Uint8Array> read( in string path, [optional] in object options )
path
options
Optionalbytes
encoding
TextDecoder
, you can supply a string to this option. For example, instead of:
let decoder = new TextDecoder(); let promise = OS.File.read("file.txt"); promise = promise.then( function onSuccess(array) { return decoder.decode(array); // Convert this array to a text } );You can simply do:
let promise = OS.File.read("file.txt", { encoding: "utf-8" }); promise = promise.then( function onSuccess(text) { return text; // text is a string } );
Remove an existing file.
Promise<void> remove( in string path, [optional] in object options )
path
options
OptionalignoreAbsent
OS.File.Error
Remove an empty directory
Promise<void> removeEmptyDir( in string path, [optional] in object options )
path
ignoreAbsent
OS.File.Error
Remove an existing directory and its contents.
Promise<void> removeDir( in string path, [optional] in object options )
path
options
ignoreAbsent
ignorePermissions
OS.File.Error
Change the current directory of the process.
Use with extreme caution: This API may be useful for application developers but must not be used by add-ons, as it changes the state of the complete application.
Promise<void> setCurrentDirectory( in string path )
path
OS.File.Error
Set the last access and modification date of the file.
The time stamp resolution is one second at best, but might be worse depending on the platform, file system, etc.
Promise<void> setDates( in string path, in Date|number accessDate, in Date|number modificationDate )
OS.File.Error
Sets the file's access permission bits.
Promise<void> setPermissions( in string path, in object options )
winAttributes
hidden
readOnly
system
unixMode
OS.Constants.libc.S_I*
or OS.Constants.libc.S_O*
. Ignored under non-Unix platforms. To make a file hidden on Unix based platforms, including Mac, simply rename the file with OS.File.move
to have "." at the start of the file name.unixHonorUmask
OS.Constants.Sys.umask
flag. Ignored under non-Unix platforms..OS.File.Error
Obtain information about a file, such as size, creation date, etc.
Promise<File.Info> stat( in string path )
path
An instance of File.Info holding information about a file.
OS.File.Error
Performance Note: If the file is already opened, calling method stat()
is much faster than calling function OS.File.stat().
Create a symoblic link file, also known as "Alias" files on Mac OS. This is similar to "Shortcut" files on Windows systems. This function is specific to UNIX baed systems such as Linux and Mac OS X.
Promise<undefined> unixSymLink( in string pathTarget, in string pathCreate )
pathTarget
pathCreate
.link.
undefined
OS.File.Error
Write data to a file, atomically.
Unlike a regular write
, this operation ensures that, until the contents are fully written, the destination file is not modified.
Promise<void> writeAtomic( in string path, in ArrayBufferView data, in object options )
path
data
As of Firefox 37, this method will neuter the array buffer.
options
tmpPath
null
or unspecified, write the data directly to path
. If specified, write the data to a temporary file called tmpPath
and, once the write is complete, rename the file to replace path
. Performing this operation is a little slower but also a little safer. tmpPath is required in Firefox 24 or lower version, but optional in Firefox 25 or higher version
noOverwrite
path
already exists, this function will throw an error without overwriting path
.flush
false
or unspecified, return immediately once the write is complete. If true
, before writing, force the operating system to write its internal disk buffers to the disk. This is considerably slower (not just for the application but for the whole system) and more battery expensive but also safer: if the system shuts down improperly (typically due to a kernel freeze or a power failure) or if the device is disconnected before the buffer is flushed, the file has more chances of not being corrupted.backupTo
backupTo
. Note that this function renames the destination file before overwriting it. If the process or the operating system freezes or crashes during the short window between these operations, the destination file will have been moved to its backup.encoding
TextEncoder
, you can supply a string to this option. For example, instead of:
let encoder = new TextEncoder(); let array = encoder.encode("This is some text"); let promise = OS.File.writeAtomic("file.txt", array, {tmpPath: "file.txt.tmp"});You can simply do:
let promise = OS.File.writeAtomic("file.txt", "This is some text", { encoding: "utf-8", tmpPath: "file.txt.tmp" })
Limitations
In a few extreme cases (hardware failure during the write, user unplugging disk during the write, etc.), data may be corrupted. If your data is user-critical (e.g., preferences, application data), you may wish to consider adding options tmpPath
and/or flush
to reduce the likelihood of corruption, as detailed above. Note that no combination of options can be guaranteed to totally eliminate the risk of corruption.
Use with caution: Modifying the contents of data
before the operation is complete is a very bad idea.
tmpPath
is not on the same device as path
.To obtain an instance of OS.File, use function OS.File.open.
Promise<void> close() |
Promise<void> flush() |
Promise<number> getPosition() |
Promise<number> read([optional] in number bytes) |
Promise<void> setDates(in Date|number accessDate, in Date|number modificationDate); |
Promise<void> setPosition(in number bytes) |
Promise<File.Info> stat() |
Promise<number> write(in ArrayBufferView source, [optional] in object options) |
Close a file and release any associated resource.
Once the file is closed, any attempt to call methods of the file object will raise an error.
An example is seen here. In this example the contents is not written to file until .close is called.
Note that the operating system limits the number of files that can be opened simultaneously by one process, so do not forget to close
that file once you have finished it to make sure that you are not blocking the rest of the process.
Promise<void> close()
Flushes the file's internal buffers, ensuring that all data still in these buffers is now written to disk.
Disk flushes are very expensive and therefore should be used carefully, sparingly, and only in scenarios where it is vital that data survives system crashes. Even though the function will be executed off the main-thread, it might still affect the overall performance of any running application.
Promise<void> flush()
Return the current position in the file.
Promise<number> getPosition()
The current position in the file, as a number of bytes from the start.
OS.File.Error
Read bytes from this file to a new buffer. Bytes are read from the current position in the file and the position is advanced accordingly.
Promise<Uint8Array> read( [optional] in number bytes )
bytes
bytes
bytes, or less if the file does not contain that many bytes. If unspecified, read all the remaining bytes from this file.An array containing the bytes read.
If you need to convert the result of this function to a string, you may do so by using the StringEncoding API.
OS.File.Error
Set the last access and modification date of the file.
The time stamp resolution is one second at best, but might be worse depending on the platform, file system, etc.
Promise<void> setDates( in Date|number accessDate, in Date|number modificationDate )
OS.File.Error
Change the current position in the file.
Promise<void> setPosition( in number offset, in object origin )
offset
origin
OS.File.POS_START
(bytes are counted from the start of the file)OS.File.POS_CUR
(bytes are counted from the current position in the file)OS.File.POS_END
(bytes are counted from the end of the file)OS.File.Error
Obtain information about the file, such as size, creation date, etc.
Promise<File.Info> stat()
An instance of File.Info holding information about the file.
OS.File.Error
Write bytes from a buffer to this file.
Note that, by default, this function may perform several I/O operations to ensure that the buffer is fully written.
An example is seen here.
Promise<number> write( in ArrayBufferView source [optional] in object options )
source
As of Firefox 37, this method will neuter the array buffer.
options
Optionalbytes
source.byteLength
bytes. If specified, this must be less than source.byteLength
.The number of bytes effectively written to the file.
OS.File.Error
TypeError
options.bytes
is specified and is larger than source.byteLength
.