mozilla

Revision 516521 of File I/O

  • Revision slug: Mozilla/Add-ons/Code_snippets/File_I_O
  • Revision title: File I/O
  • Revision id: 516521
  • Created:
  • Creator: Noitidart
  • Is current revision? No
  • Comment added a copy paste example of async read and write file combined example

Revision Content

This article describes local file input/output in chrome JavaScript.

You access the file system using Mozilla XPCOM components.

Note: File objects are {{ interface("nsIFile") }} or extended to {{ interface("nsILocalFile") }} see them for more information.

Available libraries

There are a few JavaScript wrappers for I/O XPCOM components. See JSLib.

Creating an {{ interface("nsIFile") }} object

Components.utils.import("resource://gre/modules/FileUtils.jsm");

var file = new FileUtils.File("/home");

Or the same without using FileUtils.jsm:

var file = Components.classes["@mozilla.org/file/local;1"].
           createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("/home");

{{ NoteStart() }}The path should be in the "native" form (for example "C:\\Windows"). If you need to use file:// URIs as initializers, see discussion of {{ interface("nsIIOService") }} below.{{ NoteEnd() }} {{ NoteStart() }}You can still get a file object even if the specified file does not exist, no exception will be thrown. An exception is thrown when methods that require the file existence are called, for example isDirectory(), moveTo(), and so on. Use file.exists() to check whether the file exists.{{ NoteEnd() }}

Getting files in special directories

Components.utils.import("resource://gre/modules/FileUtils.jsm");

// get the "data.txt" file in the profile directory
var file = FileUtils.getFile("ProfD", ["data.txt"]);

Or the same without using FileUtils.jsm:

// get profile directory
var file = Components.classes["@mozilla.org/file/directory_service;1"].
           getService(Components.interfaces.nsIProperties).
           get("ProfD", Components.interfaces.nsIFile);
file.append("data.txt");

// Note: "file" is an object that implements nsIFile. If you want the
// file system path, use file.path

{{ NoteStart() }}file is an object that implements {{ interface("nsIFile") }}. If you want the file system path, use file.path,{{ NoteEnd() }}

Here are some strings you can put in place of "ProfD" (stolen from MonkeeSage's I/O module comments):

String Meaning
AChrom %CurProcD%/chrome
APlugns %CurProcD%/plugins
ComsD %CurProcD%/components
CurProcD Current working directory (usually the application's installation directory).
DefProfRt The root of the default profile directory (for example /root/.mozilla).
DefRt %CurProcD%/defaults
Desk The user's desktop directory (for example ~/Desktop on Linux or Mac OS X, C:\Documents and Settings\username\Desktop on Windows).
DfltDwnld The default Downloads directory (for example, ~/Downloads on Mac OS X).
Home The user's home directory (for example, /home/username).
PrfDef %installation%/defaults/pref
ProfD The profile directory.
ProfDefNoLoc %installation%/defaults/profile
ProfLD Local Settings on Windows; where the network cache and fastload files are stored.
Progs User Start menu programs directory (for example, C:\Documents and Settings\username\Start Menu\Programs). This is a Windows-specific value.
TmpD The operating system's temporary files directory (for example, /tmp on Mac OS X and Linux).
UChrm The user chrome directory in their profile: %profile%/chrome.
resource:app The application directory in a XULRunner application.

Look in the source for other strings available: {{ source("xpcom/io/nsAppDirectoryServiceDefs.h") }}, {{ source("xpcom/io/nsDirectoryServiceDefs.h") }}.

Enumerating drives on Windows

While you can use initWithPath("/") on UNIX-like systems (Linux, Mac) to get the root of the file system, there's no such root on Windows. However, you can enumerate available drives using the following code:

Components.utils.import("resource://gre/modules/FileUtils.jsm");

var root = new FileUtils.File("\\\\.");
var drivesEnum = root.directoryEntries, drives = [];
while (drivesEnum.hasMoreElements()) {
  drives.push(drivesEnum.getNext().
    QueryInterface(Components.interfaces.nsILocalFile).path);
}

Creating Folders

FileUtils.getDir() can create a folder automatically if it doesn't exist yet:

Components.utils.import("resource://gre/modules/FileUtils.jsm");

var dir = FileUtils.getDir("ProfD", ["DIR"], true);

The above example creates a folder called "DIR" in the user's profile folder. You can also create a directory explicitly, for more information refer to {{ ifmethod("nsIFile","create") }}.

Creating temporary files

To create a temporary file, use {{ ifmethod("nsIFile","createUnique") }}:

Components.utils.import("resource://gre/modules/FileUtils.jsm");

var file = FileUtils.getFile("TmpD", ["suggestedName.tmp"]);
file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
// do whatever you need to the created file
alert(file.path);

User input via {{ interface("nsIFilePicker") }}

The file picker component, {{ interface("nsIFilePicker") }}, can be used to open standard Open / Save dialogs. It returns the user-specified file as {{ interface("nsIFile") }}.

{{ interface("nsIFile") }} and path strings

You can use nsIFile.path to get platform-specific path string, for example "C:\Windows\System32" or "/usr/share".

To get a URL of a file, use {{ ifmethod("nsIIOService","newFileURI") }}:

// file is nsIFile
Components.utils.import("resource://gre/modules/Services.jsm");
var url = services.io.newFileURI(file);
// url is a nsIURI; to get the string "file://...", see url.spec

To get a {{ interface("nsIFile") }} from the 'file://' URL, use {{ interface("nsIFileURL") }}:

// url is a nsIURI; see nsIIOService::newURI for getting a string into a nsIURI.
var file = url.QueryInterface(Components.interfaces.nsIFileURL).file;
// file is now a nsIFile

To load from file://, http://, chrome://, resource:// and other URLs directly, use XMLHttpRequest or NetUtil.asyncFetch().

Also note that generally you don't need to use nsIFile::path. Use nsIFile directly wherever possible. An example below shows how you should save a path in user prefs.

Storing nsILocalFile in preferences

The following two snippets show the right way to store a file path in user preferences (more about preferences in Mozilla):

Absolute path (nsILocalFile)

To store arbitrary path in user preferences, use this code.

// |file| is nsILocalFile
// 1. Write path to prefs
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
            getService(Components.interfaces.nsIPrefService).
            getBranch("extensions.myext.");
prefs.setComplexValue("filename", Components.interfaces.nsILocalFile, file);

// 2. Read path from prefs
var file = prefs.getComplexValue("filename", Components.interfaces.nsILocalFile);

Relative path (nsIRelativeFilePref)

To store paths relative to one of the predefined folders listed above, for example file relative to profile folder, use the following code:

// 1. Write to prefs
var relFile = Components.classes["@mozilla.org/pref-relativefile;1"].
              createInstance(Components.interfaces.nsIRelativeFilePref);
relFile.relativeToKey = "ProfD"; // or any other string listed above
relFile.file = file;             // |file| is nsILocalFile
prefs.setComplexValue("filename", 
     Components.interfaces.nsIRelativeFilePref, relFile);

// 2. Read from prefs
var value = prefs.getComplexValue("filename", 
     Components.interfaces.nsIRelativeFilePref);
// |value.file| is the file.

Get a file in given directory

Let us assume a {{ interface("nsIFile") }} file is pointing to some directory (for example a user profile directory), then you may use file.append("myfile.txt"); to make it point to myfile.txt inside that directory.

Note: Avoid using dir.path+"\\"+"myfile.txt", as it is not cross-platform at all. Using something like ((path.search(/\\/) != -1) ? path + "\\" : path + "/") + "myfile.txt"; is possible, but {{ ifmethod("nsIFile","append") }} is much easier to read and is guaranteed to work on all platforms Mozilla itself works.

Enumerating files in given directory

The snippet below makes an array of{{ interface("nsIFile") }}s corresponding to sub-directories/"sub-files" of given directory. You can tell files from folders by calling {{ ifmethod("nsIFile","isDirectory") }} and {{ ifmethod("nsIFile","isFile") }} methods on each entry.

// file is the given directory (nsIFile)
var entries = file.directoryEntries;
var array = [];
while(entries.hasMoreElements())
{
  var entry = entries.getNext();
  entry.QueryInterface(Components.interfaces.nsIFile);
  array.push(entry);
}

Reading from a file

Read into a stream or a string

This will allow you to read a file without locking up the UI thread.  This sample code uses NetUtil.jsm. You can pass an {{ interface("nsIFile") }} object directly into NetUtil.asyncFetch:

Components.utils.import("resource://gre/modules/NetUtil.jsm");

NetUtil.asyncFetch(file, function(inputStream, status) {
  if (!Components.isSuccessCode(status)) {
    // Handle error!
    return;
  }

  // The file data is contained within inputStream.
  // You can read it into a string with
  var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
});

Read with content type hint

It's useful to provide a content type hint to prevent the file system from doing a potentially expensive content type look up (which would be synchronous I/O). In this case the an {{ interface("nsIChannel") }} object has to be explicitly created from the file:

Components.utils.import("resource://gre/modules/NetUtil.jsm");
// Content type hint is useful on mobile platforms where the filesystem
// would otherwise try to determine the content type.
var channel = NetUtil.newChannel(file);
channel.contentType = "application/json";

NetUtil.asyncFetch(channel, function(inputStream, status) {
  ...
});

Writing to a file

Write a string

This sample uses NetUtil.jsm and FileUtils.jsm.

Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");

// file is nsIFile, data is a string

// You can also optionally pass a flags parameter here. It defaults to
// FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
var ostream = FileUtils.openSafeFileOutputStream(file)

var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
                createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(data);

// The last argument (the callback) is optional.
NetUtil.asyncCopy(istream, ostream, function(status) {
  if (!Components.isSuccessCode(status)) {
    // Handle error!
    return;
  }

  // Data has been written to the file.
});

Copy a stream to a file

This function copies all of the data from an input stream to a file asyncronously.  It takes an {{ interface("nsIInputStream") }} and an {{ interface("nsIFile") }} as arguments, and uses NetUtil.jsm and FileUtils.jsm. The callback argument is optional.

function StreamToFile(stream, file, callback)
{
    var output = FileUtils.openSafeFileOutputStream(file)
    NetUtil.asyncCopy(stream, output, callback);
}

Combined Example of Reading and Writing to File (Asyncyronus)

This combines examples from the above "Reading" and "Writing" examples to create read and overwrite functions. This is a copy paste example, copy it, open scratchpad, set environment to "Browser", paste this and run it.

/*start - example usage*/
  var file = FileUtils.getFile("Desk", ["rawr.txt"]); //this gets file on desktop named 'rawr.txt'
  //can also go: var file = FileUtils.File('C:\\Documents and Settings\\My User Name\\Desktop\\rawr.txt');

  overwriteFile(file, 'blah blah blah', function (status) {
	  Components.utils.reportError('overwrite status == ' + Components.isSuccessCode(status));
  });

  readFile(file, function (dataReadFromFile, status) {
	   Components.utils.reportError('file read status == ' + Components.isSuccessCode(status));
	   Components.utils.reportError('contents of file is:\n' + dataReadFromFile);
  });
/*end - example usage*/





Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
function overwriteFile(nsiFile, data, callback) {
	//data is data you want to write to file
	//if file doesnt exist it is created
	var ostream = FileUtils.openSafeFileOutputStream(file)
	var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
	converter.charset = "UTF-8";
	var istream = converter.convertToInputStream(data);
	// The last argument (the callback) is optional.
	NetUtil.asyncCopy(istream, ostream, function (status) {
		if (!Components.isSuccessCode(status)) {
			// Handle error!
			 Components.utils.reportError('error on write isSuccessCode = ' + status);
			return;
		}
		// Data has been written to the file.
		callback(status)
	});
}

function readFile(nsiFile, callback) {
	//you must pass a callback like function(dataReadFromFile, status) { }
	//then within the callback you can work with the contents of the file, it is held in dataReadFromFile
	//callback gets passed the data as string
	NetUtil.asyncFetch(file, function (inputStream, status) {
		//this function is callback that runs on completion of data reading
		if (!Components.isSuccessCode(status)) {
			 Components.utils.reportError('error on file read isSuccessCode = ' + status);
			return;
		}
		var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
		callback(data, status);
	});
}

Synchronous

{{ Storage:synchronous_io_warning() }}

Reading a file

// |file| is nsIFile
var data = "";
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
              createInstance(Components.interfaces.nsIFileInputStream);
var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
              createInstance(Components.interfaces.nsIConverterInputStream);
fstream.init(file, -1, 0, 0);
cstream.init(fstream, "UTF-8", 0, 0); // you can use another encoding here if you wish

let (str = {}) {
  let read = 0;
  do { 
    read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value
    data += str.value;
  } while (read != 0);
}
cstream.close(); // this closes fstream

alert(data);

Reading Line by Line

{{ Storage:synchronous_io_warning() }}

NOTE: The sample code below does not handle text with non-ASCII characters. See Reading textual data details on how to read text from other character sets.
// open an input stream from file
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].
              createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);

// read lines into array
var line = {}, lines = [], hasmore;
do {
  hasmore = istream.readLine(line);
  lines.push(line.value); 
} while(hasmore);

istream.close();

// do something with read data
alert(lines);

Reading a Binary File

{{ Storage:synchronous_io_warning() }}

For instance, to get the data in a PNG file:

var ios = Components.classes["@mozilla.org/network/io-service;1"].
          getService(Components.interfaces.nsIIOService);
var url = ios.newURI(aFileURL, null, null);

if (!url || !url.schemeIs("file")) throw "Expected a file URL.";

var pngFile = url.QueryInterface(Components.interfaces.nsIFileURL).file;

var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].
              createInstance(Components.interfaces.nsIFileInputStream);
istream.init(pngFile, -1, -1, false);

var bstream = Components.classes["@mozilla.org/binaryinputstream;1"].
              createInstance(Components.interfaces.nsIBinaryInputStream);
bstream.setInputStream(istream);

var bytes = bstream.readBytes(bstream.available());

Writing a File

{{ Storage:synchronous_io_warning() }}

// file is nsIFile, data is a string
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
               createInstance(Components.interfaces.nsIFileOutputStream);

// use 0x02 | 0x10 to open file for appending.
foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
// write, create, truncate
// In a c file operation, we have no need to set file mode with or operation,
// directly using "r" or "w" usually.

// if you are sure there will never ever be any non-ascii text in data you can 
// also call foStream.write(data, data.length) directly
var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].
                createInstance(Components.interfaces.nsIConverterOutputStream);
converter.init(foStream, "UTF-8", 0, 0);
converter.writeString(data);
converter.close(); // this closes foStream
Note: The file status flags used in the {{ ifmethod("nsIFileOutputStream","init") }} function are documented in PR_Open. For more information refer directly to {{ source("nsprpub/pr/include/prio.h") }}

Writing a Binary File

{{ Storage:synchronous_io_warning() }}

For example, here we can write PNG data to a file.

// pngBinary already exists
var aFile = Components.classes["@mozilla.org/file/local;1"].
            createInstance(Components.interfaces.nsILocalFile);

aFile.initWithPath( "/tmp/mypicture.png" );
aFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
            
var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
             createInstance(Components.interfaces.nsIFileOutputStream);
stream.init(aFile, 0x04 | 0x08 | 0x20, 0600, 0); // readwrite, create, truncate
            
stream.write(pngBinary, pngBinary.length);
if (stream instanceof Components.interfaces.nsISafeOutputStream) {
    stream.finish();
} else {
    stream.close();
}

More

There are more methods and properties on {{ interface("nsIFile") }} and {{ interface("nsILocalFile") }} interfaces, please refer to their documentation for more details. Those methods/properties are mostly self-explanatory, so we haven't included examples of using them here.

{{ languages( { "fr": "fr/Extraits_de_code/Fichiers_E//S", "ja": "ja/Code_snippets/File_I//O", "pl": "pl/Fragmenty_kodu/Plik_I//O" } ) }}

Revision Source

<p>This article describes local file input/output in chrome JavaScript.</p>
<p>You access the file system using Mozilla <a href="/en/XPCOM" title="en/XPCOM">XPCOM</a> components.</p>
<div class="note">
 <strong>Note</strong>: File objects are {{ interface("nsIFile") }} or extended to {{ interface("nsILocalFile") }} see them for more information.</div>
<h3 id="Available_libraries" name="Available_libraries">Available libraries</h3>
<p>There are a few JavaScript wrappers for I/O XPCOM components. See <a class="external" href="http://jslib.mozdev.org/">JSLib</a>.</p>
<h3 id="Creating_a_file_object" name="Creating_a_file_object">Creating an {{ interface("nsIFile") }} object</h3>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/FileUtils.jsm");

var file = new FileUtils.File("/home");
</pre>
<p>Or the same without using <a href="/en-US/docs/JavaScript_code_modules/FileUtils.jsm" title="en-US/docs/JavaScript_code_modules/FileUtils.jsm">FileUtils.jsm</a>:</p>
<pre class="brush: js">
var file = Components.classes["@mozilla.org/file/local;1"].
           createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("/home");
</pre>
<p>{{ NoteStart() }}The path should be in the "native" form (for example <code>"C:\\Windows"</code>). If you need to use file:// URIs as initializers, see discussion of {{ interface("nsIIOService") }} below.{{ NoteEnd() }} {{ NoteStart() }}You can still get a file object even if the specified file does not exist, no exception will be thrown. An exception is thrown when methods that require the file existence are called, for example <code>isDirectory()</code>, <code>moveTo()</code>, and so on. Use <code>file.exists()</code> to check whether the file exists.{{ NoteEnd() }}</p>
<h3 id="Getting_files_in_special_directories" name="Getting_files_in_special_directories">Getting files in special directories</h3>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/FileUtils.jsm");

// get the "data.txt" file in the profile directory
var file = FileUtils.getFile("ProfD", ["data.txt"]);
</pre>
<p>Or the same without using <a href="/en-US/docs/JavaScript_code_modules/FileUtils.jsm" title="en-US/docs/JavaScript_code_modules/FileUtils.jsm">FileUtils.jsm</a>:</p>
<pre class="brush: js">
// get profile directory
var file = Components.classes["@mozilla.org/file/directory_service;1"].
           getService(Components.interfaces.nsIProperties).
           get("ProfD", Components.interfaces.nsIFile);
file.append("data.txt");

// Note: "file" is an object that implements nsIFile. If you want the
// file system path, use file.path
</pre>
<p>{{ NoteStart() }}<code>file</code> is an object that implements {{ interface("nsIFile") }}. If you want the file system path, use <code>file.path</code>,{{ NoteEnd() }}</p>
<p>Here are some strings you can put in place of <code>"ProfD"</code> (stolen from MonkeeSage's I/O module comments):</p>
<table class="standard-table">
 <thead>
  <tr>
   <th>String</th>
   <th>Meaning</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>AChrom</td>
   <td><code>%</code>CurProcD<code>%/chrome</code></td>
  </tr>
  <tr>
   <td>APlugns</td>
   <td><code>%</code>CurProcD<code>%/plugins</code></td>
  </tr>
  <tr>
   <td>ComsD</td>
   <td><code>%</code>CurProcD<code>%/components</code></td>
  </tr>
  <tr>
   <td>CurProcD</td>
   <td>Current working directory (usually the application's installation directory).</td>
  </tr>
  <tr>
   <td>DefProfRt</td>
   <td>The root of the default profile directory (for example <code>/root/.mozilla</code>).</td>
  </tr>
  <tr>
   <td>DefRt</td>
   <td><code>%</code>CurProcD<code>%/defaults</code></td>
  </tr>
  <tr>
   <td>Desk</td>
   <td>The user's desktop directory (for example <code>~/Desktop</code> on Linux or Mac OS X, <code>C:\Documents and Settings\username\Desktop</code> on Windows).</td>
  </tr>
  <tr>
   <td>DfltDwnld</td>
   <td>The default Downloads directory (for example, <code>~/Downloads</code> on Mac OS X).</td>
  </tr>
  <tr>
   <td>Home</td>
   <td>The user's home directory (for example, <code>/home/username</code>).</td>
  </tr>
  <tr>
   <td>PrfDef</td>
   <td><code>%installation%/defaults/pref</code></td>
  </tr>
  <tr>
   <td>ProfD</td>
   <td>The profile directory.</td>
  </tr>
  <tr>
   <td>ProfDefNoLoc</td>
   <td><code>%installation%/defaults/profile</code></td>
  </tr>
  <tr>
   <td>ProfLD</td>
   <td>Local Settings on Windows; where the network cache and fastload files are stored.</td>
  </tr>
  <tr>
   <td>Progs</td>
   <td>User Start menu programs directory (for example, <code>C:\Documents and Settings\username\Start Menu\Programs</code>). This is a Windows-specific value.</td>
  </tr>
  <tr>
   <td>TmpD</td>
   <td>The operating system's temporary files directory (for example, <code>/tmp</code> on Mac OS X and Linux).</td>
  </tr>
  <tr>
   <td>UChrm</td>
   <td>The user chrome directory in their profile: <code>%profile%/chrome</code>.</td>
  </tr>
  <tr>
   <td>resource:app</td>
   <td>The application directory in a XULRunner application.</td>
  </tr>
 </tbody>
</table>
<p>Look in the source for other strings available: {{ source("xpcom/io/nsAppDirectoryServiceDefs.h") }}, {{ source("xpcom/io/nsDirectoryServiceDefs.h") }}.</p>
<h4 id="Enumerating_drives_on_Windows">Enumerating drives on Windows</h4>
<p>While you can use <code>initWithPath("/") </code>on UNIX-like systems (Linux, Mac) to get the root of the file system, there's no such root on Windows. However, you can enumerate available drives using the following code:</p>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/FileUtils.jsm");

var root = new FileUtils.File("\\\\.");
var drivesEnum = root.directoryEntries, drives = [];
while (drivesEnum.hasMoreElements()) {
  drives.push(drivesEnum.getNext().
    QueryInterface(Components.interfaces.nsILocalFile).path);
}
</pre>
<h3 id="Creating_Folders" name="Creating_Folders">Creating Folders</h3>
<p><a href="/en-US/docs/JavaScript_code_modules/FileUtils.jsm#getDir%28%29" title="en-US/docs/JavaScript_code_modules/FileUtils.jsm#getDir%28%29">FileUtils.getDir()</a> can create a folder automatically if it doesn't exist yet:</p>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/FileUtils.jsm");

var dir = FileUtils.getDir("ProfD", ["DIR"], true);
</pre>
<p>The above example creates a folder called <code>"DIR"</code> in the user's profile folder. You can also create a directory explicitly, for more information refer to {{ ifmethod("nsIFile","create") }}.</p>
<h3 id="Creating_temporary_files" name="Creating_temporary_files">Creating temporary files</h3>
<p>To create a temporary file, use {{ ifmethod("nsIFile","createUnique") }}:</p>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/FileUtils.jsm");

var file = FileUtils.getFile("TmpD", ["suggestedName.tmp"]);
file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
// do whatever you need to the created file
alert(file.path);
</pre>
<h3 id="User_input_via_nsIFilePicker" name="User_input_via_nsIFilePicker">User input via {{ interface("nsIFilePicker") }}</h3>
<p>The file picker component, {{ interface("nsIFilePicker") }}, can be used to open standard Open / Save dialogs. It returns the user-specified file as {{ interface("nsIFile") }}.</p>
<h3 id="nsIFile_and_path_strings" name="nsIFile_and_path_strings">{{ interface("nsIFile") }} and path strings</h3>
<p>You can use <code>nsIFile.path</code> to get platform-specific path string, for example <code>"C:\Windows\System32"</code> or <code>"/usr/share"</code>.</p>
<p>To get a URL of a file, use {{ ifmethod("nsIIOService","newFileURI") }}:</p>
<pre class="brush: js">
// file is nsIFile
Components.utils.import("resource://gre/modules/Services.jsm");
var url = services.io.newFileURI(file);
// url is a nsIURI; to get the string "file://...", see url.spec
</pre>
<p>To get a {{ interface("nsIFile") }} from the 'file://' URL, use {{ interface("nsIFileURL") }}:</p>
<pre class="brush: js">
// url is a nsIURI; see nsIIOService::newURI for getting a string into a nsIURI.
var file = url.QueryInterface(Components.interfaces.nsIFileURL).file;
// file is now a nsIFile
</pre>
<p>To load from <em>file://</em>, <em>http://</em>, <em>chrome://</em>, <em>resource://</em> and other URLs directly, use <a href="/en-US/docs/DOM/XMLHttpRequest" title="en-US/docs/DOM/XMLHttpRequest">XMLHttpRequest</a> or <a href="/en-US/docs/JavaScript_code_modules/NetUtil.jsm#asyncFetch%28%29" title="en-US/docs/JavaScript_code_modules/NetUtil.jsm#asyncFetch%28%29">NetUtil.asyncFetch()</a>.</p>
<p>Also note that generally you don't need to use <code>nsIFile::path</code>. Use <code>nsIFile</code> directly wherever possible. An example below shows how you should save a path in user prefs.</p>
<h3 id="Storing_nsILocalFile_in_preferences" name="Storing_nsILocalFile_in_preferences">Storing nsILocalFile in preferences</h3>
<p>The following two snippets show the right way to store a file path in user preferences (<a href="/en/Code_snippets/Preferences" title="en/Code_snippets/Preferences">more about preferences in Mozilla</a>):</p>
<h4 id="Absolute_path_.28nsILocalFile.29" name="Absolute_path_.28nsILocalFile.29">Absolute path (nsILocalFile)</h4>
<p>To store arbitrary path in user preferences, use this code.</p>
<pre class="brush: js">
// |file| is nsILocalFile
// 1. Write path to prefs
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
            getService(Components.interfaces.nsIPrefService).
            getBranch("extensions.myext.");
prefs.setComplexValue("filename", Components.interfaces.nsILocalFile, file);

// 2. Read path from prefs
var file = prefs.getComplexValue("filename", Components.interfaces.nsILocalFile);
</pre>
<h4 id="Relative_path_.28nsIRelativeFilePref.29" name="Relative_path_.28nsIRelativeFilePref.29">Relative path (nsIRelativeFilePref)</h4>
<p>To store paths relative to one of the predefined folders listed above, for example file relative to profile folder, use the following code:</p>
<pre class="brush: js">
// 1. Write to prefs
var relFile = Components.classes["@mozilla.org/pref-relativefile;1"].
              createInstance(Components.interfaces.nsIRelativeFilePref);
relFile.relativeToKey = "ProfD"; // or any other string listed above
relFile.file = file;             // |file| is nsILocalFile
prefs.setComplexValue("filename", 
     Components.interfaces.nsIRelativeFilePref, relFile);

// 2. Read from prefs
var value = prefs.getComplexValue("filename", 
     Components.interfaces.nsIRelativeFilePref);
// |value.file| is the file.
</pre>
<h3 id="Navigating_with_nsIFile" name="Navigating_with_nsIFile">Navigating with {{ interface("nsIFile") }}</h3>
<h4 id="Get_a_file_in_given_directory" name="Get_a_file_in_given_directory">Get a file in given directory</h4>
<p>Let us assume a {{ interface("nsIFile") }} file is pointing to some directory (for example a user profile directory), then you may use <code>file.append("myfile.txt");</code> to make it point to <code>myfile.txt</code> inside that directory.</p>
<div class="note">
 <strong>Note</strong>: Avoid using <code>dir.path+"\\"+"myfile.txt"</code>, as it is not cross-platform at all. Using something like <code>((path.search(/\\/) != -1) ? path + "\\" : path + "/") + "myfile.txt";</code> is possible, but {{ ifmethod("nsIFile","append") }} is much easier to read and is guaranteed to work on all platforms Mozilla itself works.</div>
<h4 id="Enumerating_files_in_given_directory" name="Enumerating_files_in_given_directory">Enumerating files in given directory</h4>
<p>The snippet below makes an array of{{ interface("nsIFile") }}s corresponding to sub-directories/"sub-files" of given directory. You can tell files from folders by calling {{ ifmethod("nsIFile","isDirectory") }} and {{ ifmethod("nsIFile","isFile") }} methods on each <code>entry</code>.</p>
<pre class="brush: js">
// file is the given directory (nsIFile)
var entries = file.directoryEntries;
var array = [];
while(entries.hasMoreElements())
{
  var entry = entries.getNext();
  entry.QueryInterface(Components.interfaces.nsIFile);
  array.push(entry);
}
</pre>
<h3 id="Reading_from_a_file" name="Reading_from_a_file">Reading from a file</h3>
<h4 id="Asynchronously" name="Asynchronously">Read into a stream or a string</h4>
<p>This will allow you to read a file without locking up the UI thread.&nbsp; This sample code uses <a href="/en/JavaScript_code_modules/NetUtil.jsm" title="en/JavaScript_code_modules/NetUtil.jsm">NetUtil.jsm</a>. You can pass an {{ interface("nsIFile") }} object directly into <a href="/en/JavaScript_code_modules/NetUtil.jsm#asyncFetch%28%29" title="https://developer.mozilla.org/en/JavaScript_code_modules/NetUtil.jsm#asyncFetch()">NetUtil.asyncFetch</a>:</p>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/NetUtil.jsm");

NetUtil.asyncFetch(file, function(inputStream, status) {
  if (!Components.isSuccessCode(status)) {
    // Handle error!
    return;
  }

  // The file data is contained within inputStream.
  // You can read it into a string with
  var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
});
</pre>
<h4 id="Read_with_content_type_hint">Read with content type hint</h4>
<p>It's useful to provide a content type hint to prevent the file system from doing a potentially expensive content type look up (which would be synchronous I/O). In this case the an {{ interface("nsIChannel") }} object has to be explicitly created from the file:</p>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/NetUtil.jsm");
// Content type hint is useful on mobile platforms where the filesystem
// would otherwise try to determine the content type.
var channel = NetUtil.newChannel(file);
channel.contentType = "application/json";

NetUtil.asyncFetch(channel, function(inputStream, status) {
  ...
});
</pre>
<h3 id="Writing_to_a_file" name="Writing_to_a_file">Writing to a file</h3>
<h4 id="Write_a_string">Write a string</h4>
<p>This sample uses <a href="/en/JavaScript_code_modules/NetUtil.jsm" title="en/JavaScript_code_modules/NetUtil.jsm">NetUtil.jsm</a> and <a href="/en/JavaScript_code_modules/FileUtils.jsm" title="en/JavaScript code modules/FileUtils.jsm">FileUtils.jsm</a>.</p>
<pre class="brush: js">
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");

// file is nsIFile, data is a string

// You can also optionally pass a flags parameter here. It defaults to
// FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
var ostream = FileUtils.openSafeFileOutputStream(file)

var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
                createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(data);

// The last argument&nbsp;(the callback) is optional.
NetUtil.asyncCopy(istream, ostream, function(status) {
  if (!Components.isSuccessCode(status)) {
    // Handle error!
    return;
  }

  // Data has been written to the file.
});
</pre>
<h4 id="Copy_a_stream_to_a_file" name="Copy_a_stream_to_a_file">Copy a stream to a file</h4>
<p>This function copies all of the data from an input stream to a file asyncronously.&nbsp; It takes an {{ interface("nsIInputStream") }} and an {{ interface("nsIFile") }} as arguments, and uses <a href="/en/JavaScript_code_modules/NetUtil.jsm" title="en/JavaScript_code_modules/NetUtil.jsm">NetUtil.jsm</a> and <a href="/en/JavaScript_code_modules/FileUtils.jsm" title="en/JavaScript code modules/FileUtils.jsm">FileUtils.jsm</a>. The <code>callback</code> argument is optional.</p>
<pre class="brush: js">
function StreamToFile(stream, file, callback)
{
    var output = FileUtils.openSafeFileOutputStream(file)
    NetUtil.asyncCopy(stream, output, callback);
}
</pre>
<h3 id="Writing_to_a_file" name="Writing_to_a_file">Combined Example of Reading and Writing to File (Asyncyronus)</h3>
<p>This combines examples from the above "Reading" and "Writing" examples to create read and overwrite functions. This is a copy paste example, copy it, open scratchpad, set environment to "Browser", paste this and run it.</p>
<pre class="brush: js">
/*start - example usage*/
  var file = FileUtils.getFile("Desk", ["rawr.txt"]); //this gets file on desktop named 'rawr.txt'
  //can also go: var file = FileUtils.File('C:\\Documents and Settings\\My User Name\\Desktop\\rawr.txt');

  overwriteFile(file, 'blah blah blah', function (status) {
	  Components.utils.reportError('overwrite status == ' + Components.isSuccessCode(status));
  });

  readFile(file, function (dataReadFromFile, status) {
	   Components.utils.reportError('file read status == ' + Components.isSuccessCode(status));
	   Components.utils.reportError('contents of file is:\n' + dataReadFromFile);
  });
/*end - example usage*/





Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
function overwriteFile(nsiFile, data, callback) {
	//data is data you want to write to file
	//if file doesnt exist it is created
	var ostream = FileUtils.openSafeFileOutputStream(file)
	var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
	converter.charset = "UTF-8";
	var istream = converter.convertToInputStream(data);
	// The last argument (the callback) is optional.
	NetUtil.asyncCopy(istream, ostream, function (status) {
		if (!Components.isSuccessCode(status)) {
			// Handle error!
			 Components.utils.reportError('error on write isSuccessCode = ' + status);
			return;
		}
		// Data has been written to the file.
		callback(status)
	});
}

function readFile(nsiFile, callback) {
	//you must pass a callback like function(dataReadFromFile, status) { }
	//then within the callback you can work with the contents of the file, it is held in dataReadFromFile
	//callback gets passed the data as string
	NetUtil.asyncFetch(file, function (inputStream, status) {
		//this function is callback that runs on completion of data reading
		if (!Components.isSuccessCode(status)) {
			 Components.utils.reportError('error on file read isSuccessCode = ' + status);
			return;
		}
		var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
		callback(data, status);
	});
}
</pre>
<h3 id="More" name="More">Synchronous</h3>
<p>{{ Storage:synchronous_io_warning() }}</p>
<h4 id="Synchronously" name="Synchronously">Reading a file</h4>
<pre class="brush: js">
// |file| is nsIFile
var data = "";
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
              createInstance(Components.interfaces.nsIFileInputStream);
var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
              createInstance(Components.interfaces.nsIConverterInputStream);
fstream.init(file, -1, 0, 0);
cstream.init(fstream, "UTF-8", 0, 0); // you can use another encoding here if you wish

let (str = {}) {
  let read = 0;
  do { 
    read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value
    data += str.value;
  } while (read != 0);
}
cstream.close(); // this closes fstream

alert(data);</pre>
<h4 id="Line_by_line" name="Line_by_line">Reading Line by Line</h4>
<p>{{ Storage:synchronous_io_warning() }}</p>
<div class="note">
 <strong>NOTE</strong>: The sample code below does not handle text with non-ASCII characters. See <a href="/en/Reading_textual_data" title="en/Reading_textual_data">Reading textual data</a> details on how to read text from other character sets.</div>
<pre class="brush: js">
// open an input stream from file
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].
              createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);

// read lines into array
var line = {}, lines = [], hasmore;
do {
  hasmore = istream.readLine(line);
  lines.push(line.value); 
} while(hasmore);

istream.close();

// do something with read data
alert(lines);
</pre>
<h4 id="Binary_File" name="Binary_File">Reading a Binary File</h4>
<p>{{ Storage:synchronous_io_warning() }}</p>
<p>For instance, to get the data in a PNG file:</p>
<pre class="brush: js">
var ios = Components.classes["@mozilla.org/network/io-service;1"].
          getService(Components.interfaces.nsIIOService);
var url = ios.newURI(aFileURL, null, null);

if (!url || !url.schemeIs("file")) throw "Expected a file URL.";

var pngFile = url.QueryInterface(Components.interfaces.nsIFileURL).file;

var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].
              createInstance(Components.interfaces.nsIFileInputStream);
istream.init(pngFile, -1, -1, false);

var bstream = Components.classes["@mozilla.org/binaryinputstream;1"].
              createInstance(Components.interfaces.nsIBinaryInputStream);
bstream.setInputStream(istream);

var bytes = bstream.readBytes(bstream.available());
</pre>
<h4 id="Writing_a_File">Writing a File</h4>
<p>{{ Storage:synchronous_io_warning() }}</p>
<pre class="brush: js">
// file is nsIFile, data is a string
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
               createInstance(Components.interfaces.nsIFileOutputStream);

// use 0x02 | 0x10 to open file for appending.
foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
// write, create, truncate
// In a c file operation, we have no need to set file mode with or operation,
// directly using "r" or "w" usually.

// if you are sure there will never ever be any non-ascii text in data you can 
// also call foStream.write(data, data.length) directly
var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].
                createInstance(Components.interfaces.nsIConverterOutputStream);
converter.init(foStream, "UTF-8", 0, 0);
converter.writeString(data);
converter.close(); // this closes foStream
</pre>
<div class="note">
 <strong>Note</strong>: The file status flags used in the {{ ifmethod("nsIFileOutputStream","init") }} function are documented in <a href="/en/PR_Open#Parameters" title="en/PR_Open#Parameters">PR_Open</a>. For more information refer directly to {{ source("nsprpub/pr/include/prio.h") }}</div>
<h4 id="Writing_a_Binary_File" name="Writing_a_Binary_File">Writing a Binary File</h4>
<p>{{ Storage:synchronous_io_warning() }}</p>
<p>For example, here we can write PNG data to a file.</p>
<pre class="brush: js">
// pngBinary already exists
var aFile = Components.classes["@mozilla.org/file/local;1"].
            createInstance(Components.interfaces.nsILocalFile);

aFile.initWithPath( "/tmp/mypicture.png" );
aFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
            
var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
             createInstance(Components.interfaces.nsIFileOutputStream);
stream.init(aFile, 0x04 | 0x08 | 0x20, 0600, 0); // readwrite, create, truncate
            
stream.write(pngBinary, pngBinary.length);
if (stream instanceof Components.interfaces.nsISafeOutputStream) {
    stream.finish();
} else {
    stream.close();
}
</pre>
<h3 id="More" name="More">More</h3>
<p>There are more methods and properties on {{ interface("nsIFile") }} and {{ interface("nsILocalFile") }} interfaces, please refer to their documentation for more details. Those methods/properties are mostly self-explanatory, so we haven't included examples of using them here.</p>
<p>{{ languages( { "fr": "fr/Extraits_de_code/Fichiers_E//S", "ja": "ja/Code_snippets/File_I//O", "pl": "pl/Fragmenty_kodu/Plik_I//O" } ) }}</p>
Revert to this revision