MozillaZine

File IO

From MozillaZine Knowledge Base

(Difference between revisions)
Revision as of 10:26, 3 November 2004
Asqueella (Talk | contribs)
(use nsIChannel for chrome/resource urls)
<-- Previous diff
Revision as of 10:27, 3 November 2004
Asqueella (Talk | contribs)
(|file| instead of file)
Next diff -->
Line 110: Line 110:
-===Simple ===+===Simple===
-<pre>// file is nsIFile+<pre>// |file| is nsIFile
var data = ""; var data = "";
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"] var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]

Revision as of 10:27, 3 November 2004

Contents

Introduction

This article describes local file input/output in Javascript.

You access the filesystem using Mozilla XPCOM components. The list of components used for local IO is available at XulPlanet.com.

Available libraries

There are a few JavaScript wrappers for IO XPCOM components. See JSLib and MonkeeSage's IO module. MonkeeSage's module is much smaller and very easy to use (simple examples are included in the module).

Snippets using XPCOM directly

Creating a file object ("opening" files)

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

Note: the path passed to initWithPath() should be in 'native' form (eg. "C:\\Windows"). If you need to use file:// URIs as initializers, see below.

Getting special files

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

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

String Meaning
ProfD profile directory
DefProfRt user (e.g., /root/.mozilla)
UChrm %profile%/chrome
DefRt installation
PrfDef %installation%/defaults/pref
ProfDefNoLoc %installation%/defaults/profile
APlugns %installation%/plugins
AChrom %installation%/chrome
ComsD %installation%/components
CurProcD installation (usually)
Home OS root (e.g., /root)
TmpD OS tmp (e.g., /tmp)

Look in the Source for other strings available: [1] [2].

nsIFile and path strings

You can use nsIFile::path to get platform-specific path string, eg. C:\Windows\System32 or /usr/share. If you want to get a file:// URL of a file or an nsIFile from file:// URL, you need to use nsIFileProtocolHandler:

// file is nsIFile
var URL = Components.classes["@mozilla.org/network/protocol;1?name=file"]. 
	createInstance(Components.interfaces.nsIFileProtocolHandler). 
	getURLSpecFromFile(file);

To load from file://, http://, chrome://, resource:// and other URLs directly, use nsIChannel. Until a knowledge base article on nsIChannel is written, here's an example for you.

Note: do not use nsILocalFile::persistentDescriptor to get the file path!

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.

Saving path in a userpref

This snippet shows the right way to save a file path in user preferences:

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

/* You can read it later with this statement:
var file = prefs.getComplexValue("filename", Components.interfaces.nsILocalFile);
*/


Navigating with nsIFile

Get a file in given directory

Assume, file is an nsIFile pointing to some directory (f.e. a user profile directory). You can use this code: file.append("myfile.txt"); - to make file point to myfile.txt inside that directory.

Notes: avoid using dir.path+"\\"+"myfile.txt", as it is not cross-platform code. Using something like ((path.search(/\\/) != -1) ? path + "\\" : path + "/") + "myfile.txt"; is possible, but the 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 |nsIFile|s corresponding to sub-files/subdirectories of given directory. You can tell files from folders by calling nsIFile::isDirectory() and 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

Simple

// |file| is nsIFile
var data = "";
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
	.createInstance(Components.interfaces.nsIFileInputStream);
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
	.createInstance(Components.interfaces.nsIScriptableInputStream);
fstream.init(file, 1, 0, false);
sstream.init(fstream);
data += sstream.read(-1);
sstream.close();
fstream.close();
alert(data);

Line by line

// open an input stream from file
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                .createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, 0, 1, null);
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);

Writing to a file

// 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.
stream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
stream.write(data, data.length);
stream.close();