Writing to Files

File and Stream Guide: [ nsIScriptableIO | Accessing Files | Getting File Information | Reading from Files | Writing to Files | Moving, Copying and Deleting Files | Uploading and Downloading Files | Working With Directories ]

Important note: The pages from the File and Stream Guide use the IO object (nsIScriptableIO), which was not available in any released version of the platform (pending some fixes). There are alternative XPCOM APIs you can use, your help in updating this pages to use the supported API is very much welcome!

Other documentation on files and I/O not using the unavailable nsIScriptableIO APIs: Code snippets: File I/O, Open and Save Dialogs, Reading textual data, Writing textual data, List of file-related error codes.

To write to a file, an output stream is used. An output stream is an object which can be used to write bytes, strings and other values to a file. To create an output stream, use nsIScriptableIO.newOutputStream(). This method has a number of options to specify text or binary writing, the character set, and whether to append to an existing file or create a new one.

To create an input stream, first get a reference to a nsIFile, and then use nsIScriptableIO.newOutputStream() to open a stream for writing to it. To learn more about file objects, see Files and Streams.

try {
  var file = IO.getFile("Desktop", "myinfo.txt");
  var stream = IO.newOutputStream(file, "text");
} catch (ex) { alert(ex); }

This example retrieves a file object on the desktop called 'myinfo.txt' using nsIScriptableIO.getFile(). It doesn't matter whether the file exists or not. nsIScriptableIO.newOutputStream() is called to create a new output stream, which will be used to write to the file.

In this example, the operations are enclosed in a try-catch block in order to capture any errors that might occur during the process. See File Errors for a list of errors that might occur.

The newOutputStream method takes two arguments in this example. The first argument is the file to write to, and the second is a set of flags which control the writing. In this case, the 'text' flag is used which indicates that you will be writing text to the file. When writing text files, characters are writing using a chosen character set, encoded automatically. The default character set is 'UTF-8' but this can be changed using an additional, yet optional, argument to the newOutputStream method. See below for more details about this.

Creating and Appending to Files

A number of flags control whether a new file is created when writing or whether data is appended to an existing file. These flags should be included in addition to the 'text' or 'binary' flags when using the newOutputStream method. The default when writing is to create a new file when the file to write to does not exist, and replace the existing file if it does. However, there are three flags that can be used to control this behaviour.

append
if used, always write data to the end of the file. This flag is used when adding more to an existing file. If this flag is not used, the data is written at the beginning of the file, overwriting what is already there.
nocreate
if used, don't create a new file if it does not already exist. In this case, an error will occur if the file does not exist, which you can capture using a try-catch block. If this flag is not used, a new file will be created. In either case, if the file already exists, it will be truncated to zero length.
notruncate
if used, don't truncate an existing file when opening it for writing. Instead, just overwrite the existing content. If the new data being written is shorter than the existing data, the existing data will remain in the areas where no new data was written. If this flag is not used, the file is truncated before being written to.

The flags are designed such that the most common case that is needed is with no flags set, so usually you will not set these flags. However, here is an example of how they might be used:

var stream = IO.newOutputStream(file, "text nocreate append");

The flags are specified in a space separated list as the second argument to the newOutputStream method. In this example, the nocreate flag is used to prevent the creation of new files, and the append flag is used to append to an existing file.

Writing Text Files

Characters are written to a text input stream using a specified character encoding, which defaults to UTF-8. This means that a single character will occupy several bytes if it has a value greater than 128. This encoding is done automatically as long as you specify the 'text' flag to nsIScriptableIO.newOutputStream(). Other character encodings are available; see Writing Other Character Encodings below for details about writing text in other encodings.

There are several methods available to write to a stream. For text files, you will usually use the writeString method.

var file = IO.getFile("Desktop", "myinfo.txt");
var stream = IO.newOutputStream(file, "text");
stream.writeString("This is some text");
stream.close();

In this example, a text input stream is created for the file 'myinfo.txt'. The writeString method is called to write a single string to the file, supplied as an argument to the method. Finally, the stream is closed by calling the stream's close method. You should ensure that the file is closed, so that the data is properly written and that the file can be reopened for reading later.

To write additional strings, call the writeString method multiple times.

Writing Other Character Encodings

The default character encoding is UTF-8. If you want to write using a different encoding, you can specify a third argument to nsIScriptableIO.newOutputStream() which specifies the encoding. This example opens a file using the UTF-16 encoding.

var stream = IO.newInputStream(file, "text", "UTF-16");

This third argument is not needed to write using UTF-8. As UTF-8 can store all characters, you will usually always use this default. For a list of supported character encodings, see Supported Character Sets.

The files can be written using the writeString method whichever character encoding is used. The difference is handled internally so you don't need to write any other part of the code differently.

Writing Binary Data

In addition to text, binary values may be written to a file either as bytes or as numbers. A number of methods are available which may be used for this. If you are going to write to a binary file instead of text, specify the 'binary' flag in place of the 'text' flag when creating the stream with nsIScriptableIO.newOutputStream().

var stream = IO.newOutputStream(file, "binary");

This line will create and open a binary stream for a file. Once opened, you can write to the file using various writing methods. The following methods are available, all of which take one argument, which is the value to write:

  • writeBoolean will write a boolean value to a stream. If the argument is false, 0 is written, and if the argument is true, 1 is written. Non-boolean values will be converted into booleans automatically.
  • write8 will write a single byte. The 8 in the method name indicates that 8 bits of data are being written. If the supplied value is larger than 8 bits, only the lowest significant 8 bits are written.
  • write16 will write two bytes to the stream.
  • write32 will write four bytes.
  • writeFloat will write a floating point value in four bytes.
  • writeDouble will write a floating point value in eight bytes.

In this example, the write16 method is used to write the value 1000 in two bytes. The write32 method performs a similar operation except that the value 1000 is written using four bytes, padding the unused bits with zeroes.

stream.write16(1000);
stream.write32(1000);

All values are read in big endian form, which means that integers are stored in the file with their higher bits first. For the write16 and write32 methods, the values are always interpreted as unsigned values. If you want to write a negative value, use the following calculation first to convert the value:

function writeNegative(val)
{
  if (val > 0x7fff)
    val = ~(0x10000 - val - 1);
  stream.write16(val);
}

One last method that is useful for writing to binary streams is the writeByteArray method, used to write an array of bytes. This method takes an array of values and writes them all in sequence, where each element in the array is written as one byte.

stream.writeByteArray([25, 77, 46, 8]);

This example uses the writeByteArray method to write 4 bytes to the stream.