File IO: Difference between revisions
(re-format) |
|||
Line 1: | Line 1: | ||
{{extdev}} | {{extdev}} | ||
This article describes local file input/output in Javascript. | This article describes local file input/output in chrome Javascript. | ||
You access the filesystem using Mozilla [http://xulplanet.com/tutorials/xultu/xpcom.html XPCOM] components. The list of components used for local | You access the filesystem using Mozilla [http://xulplanet.com/tutorials/xultu/xpcom.html XPCOM] components. The list of components used for local I/O is available at [http://xulplanet.com/references/xpcomref/group_FilesandStreams.html XulPlanet.com]. | ||
==Available libraries== | ==Available libraries== | ||
There are a few | There are a few Javascript wrappers for I/O XPCOM components. See [http://jslib.mozdev.org/ JSLib] and MonkeeSage's [http://gratisdei.com/io.js IO module]. MonkeeSage's module is much smaller and very easy to use (simple examples are included in the module). | ||
MonkeeSage's module is much smaller and very easy to use (simple examples are included in the module). | |||
==Creating a file object ("opening" files)== | ==Creating a file object ("opening" files)== | ||
<pre>var file = Components.classes["@mozilla.org/file/local;1"]. | <pre> | ||
var file = Components.classes["@mozilla.org/file/local;1"]. | |||
createInstance(Components.interfaces.nsILocalFile); | createInstance(Components.interfaces.nsILocalFile); | ||
file.initWithPath("/home");</pre> | file.initWithPath("/home"); | ||
</pre> | |||
Note | Note, that the path passed to <code>initWithPath()</code> should be in "native" form (e.g. <tt>"C:\\Windows"</tt>). If you need to use file:// URIs as initializers, see below. | ||
Also note, that | Also note, that <code>initWithPath()</code> / <code>initWithFile()</code> functions don't throw an exception if specified file does not exist. An exception is thrown when methods that require the file existance are called, e.g. <code>isDirectory()</code>, <code>moveTo()</code> etc. | ||
==Getting special files== | ==Getting special files== | ||
Line 24: | Line 25: | ||
get("ProfD", Components.interfaces.nsIFile);</pre> | get("ProfD", Components.interfaces.nsIFile);</pre> | ||
Here are some strings you can put in place of "ProfD" (stolen from MonkeeSage's | Here are some strings you can put in place of <code>"ProfD"</code> (stolen from MonkeeSage's I/O module comments): | ||
{| border="1" cellpadding="5" rules="all" | {| border="1" cellpadding="5" rules="all" | ||
Line 56: | Line 57: | ||
Look in the Source for other strings available: [http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h] [http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h]. | Look in the Source for other strings available: [http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h] [http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h]. | ||
== | ==User input via nsIFilePicker== | ||
See [[Dev : nsIFilePicker]]. | See [[Dev : nsIFilePicker]]. | ||
==nsIFile and path strings== | ==nsIFile and path strings== | ||
You can use nsIFile::path to get platform-specific path string, | You can use <code>nsIFile::path</code> to get platform-specific path string, e.g. <tt>"C:\Windows\System32"</tt> or <tt>"/usr/share"</tt>. If you want to get a ''file://'' URL of a file or an <code>nsIFile</code> from ''file://'' URL, you need to use [http://xulplanet.com/references/xpcomref/ifaces/nsIFileProtocolHandler.html nsIFileProtocolHandler]: | ||
<pre>// file is nsIFile | <pre> | ||
// file is nsIFile | |||
var ios = Components.classes["@mozilla.org/network/io-service;1"]. | var ios = Components.classes["@mozilla.org/network/io-service;1"]. | ||
getService(Components.interfaces.nsIIOService); | getService(Components.interfaces.nsIIOService); | ||
var fileHandler = ios.getProtocolHandler("file"). | var fileHandler = ios.getProtocolHandler("file"). | ||
QueryInterface(Components.interfaces.nsIFileProtocolHandler); | QueryInterface(Components.interfaces.nsIFileProtocolHandler); | ||
var URL = fileHandler.getURLSpecFromFile(file);</pre> | var URL = fileHandler.getURLSpecFromFile(file); | ||
</pre> | |||
To load from ''file://'', ''http://'', ''chrome://'', ''resource://'' and other URLs directly, use [http://xulplanet.com/references/xpcomref/ifaces/nsIChannel.html nsIChannel]. Until a knowledge base article on | To load from ''file://'', ''http://'', ''chrome://'', ''resource://'' and other URLs directly, use <code>[http://xulplanet.com/references/xpcomref/ifaces/nsIChannel.html nsIChannel]</code>. Until a knowledge base article on that is written, [http://forums.mozillazine.org/viewtopic.php?p=921150#921150 here]'s an example for you. | ||
Note: do '''not''' use nsILocalFile::persistentDescriptor to get the file path! | Note: do '''not''' use <code>nsILocalFile::persistentDescriptor</code> 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. | 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. | ||
==Storing nsILocalFile in preferences== | ==Storing nsILocalFile in preferences== | ||
Line 111: | Line 114: | ||
===Get a file in given directory=== | ===Get a file in given directory=== | ||
Assume, | Assume, <code>file</code> is an <code>nsIFile</code> pointing to some directory (f.e. a user profile directory). You can use <code>file.append("myfile.txt");</code> to make <code>file</code> point to <tt>myfile.txt</tt> inside that directory. | ||
Note: 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> | |||
Using something like | is possible, but <code>nsIFile::append()</code> is much easier to read and is guaranteed to work on all platforms Mozilla itself works. | ||
< | |||
is possible, but | |||
===Enumerating files in given directory=== | ===Enumerating files in given directory=== | ||
The snippet below makes an array of < | The snippet below makes an array of <code>|nsIFile|</code>s corresponding to sub-directories/"sub-files" of given directory. You can tell files from folders by calling <code>nsIFile::isDirectory()</code> and <code>nsIFile::isFile()</code> methods on each <code>entry</code>. | ||
<pre>// file is the given directory (nsIFile) | <pre> | ||
// file is the given directory (nsIFile) | |||
var entries = file.directoryEntries; | var entries = file.directoryEntries; | ||
var array = []; | var array = []; | ||
Line 129: | Line 131: | ||
entry.QueryInterface(Components.interfaces.nsIFile); | entry.QueryInterface(Components.interfaces.nsIFile); | ||
array.push(entry); | array.push(entry); | ||
}</pre> | } | ||
</pre> | |||
==Reading from a file== | ==Reading from a file== | ||
===Simple=== | ===Simple=== | ||
'''Note: this code may have to be changed - see [https://bugzilla.mozilla.org/show_bug.cgi?id=278786 bug 278786]''' | |||
<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"] | ||
Line 190: | Line 193: | ||
==Writing to a file== | ==Writing to a file== | ||
<pre>// file is nsIFile, data is a string | <pre> | ||
// file is nsIFile, data is a string | |||
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] | var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] | ||
.createInstance(Components.interfaces.nsIFileOutputStream); | .createInstance(Components.interfaces.nsIFileOutputStream); | ||
// use 0x02 | 0x10 to open file for appending. | // use 0x02 | 0x10 to open file for appending. | ||
foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate | foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate | ||
foStream.write(data, data.length); | foStream.write(data, data.length); | ||
foStream.close();</pre> | foStream.close(); | ||
</pre> | |||
Flags parameter to the < | Flags parameter to the <code>nsIFileOutputStream::init()</code> function | ||
(For more information refer to [http://lxr.mozilla.org/seamonkey/source/nsprpub/pr/include/prio.h prio.h file]). | (For more information refer to [http://lxr.mozilla.org/seamonkey/source/nsprpub/pr/include/prio.h prio.h file]). | ||
Line 232: | Line 235: | ||
|} | |} | ||
[[Category:Development|File | [[Category:Development|File I/O]] [[Category:Example code|File I/O]] |
Revision as of 16:12, 2 February 2005
This page is part of the extension development documentation project.
Ask your questions in MozillaZine Forums. Also try browsing example code.
Note: development documentation is in process of being moved to Mozilla Development Center (MDC).
This article describes local file input/output in chrome Javascript.
You access the filesystem using Mozilla XPCOM components. The list of components used for local I/O is available at XulPlanet.com.
Available libraries
There are a few Javascript wrappers for I/O 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).
Creating a file object ("opening" files)
var file = Components.classes["@mozilla.org/file/local;1"]. createInstance(Components.interfaces.nsILocalFile); file.initWithPath("/home");
Note, that the path passed to initWithPath()
should be in "native" form (e.g. "C:\\Windows"). If you need to use file:// URIs as initializers, see below.
Also note, that initWithPath()
/ initWithFile()
functions don't throw an exception if specified file does not exist. An exception is thrown when methods that require the file existance are called, e.g. isDirectory()
, moveTo()
etc.
Getting special files
// get profile directory var file = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties). get("ProfD", Components.interfaces.nsIFile);
Here are some strings you can put in place of "ProfD"
(stolen from MonkeeSage's I/O module comments):
String | Meaning |
---|---|
ProfD | profile directory |
DefProfRt | user (e.g., /root/.mozilla) |
UChrm | %profile%/chrome |
DefRt | %installation%/defaults |
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].
User input via nsIFilePicker
See Dev : nsIFilePicker.
nsIFile and path strings
You can use nsIFile::path
to get platform-specific path string, e.g. "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 ios = Components.classes["@mozilla.org/network/io-service;1"]. getService(Components.interfaces.nsIIOService); var fileHandler = ios.getProtocolHandler("file"). QueryInterface(Components.interfaces.nsIFileProtocolHandler); var URL = fileHandler.getURLSpecFromFile(file);
To load from file://, http://, chrome://, resource:// and other URLs directly, use nsIChannel
. Until a knowledge base article on that 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.
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
Assume, file
is an nsIFile
pointing to some directory (f.e. a user profile directory). You can use file.append("myfile.txt");
to make file
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 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-directories/"sub-files" 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
Note: this code may have to be changed - see bug 278786
// |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, 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);
Asynchronously
This will allow you to read a file without locking up the UI thread.
// |file| is nsIFile var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var fileURI = ios.newFileURI(file); var channel = ios.newChannelFromURI(fileURI); var observer = { onStreamComplete : function(aLoader, aContext, aStatus, aLength, aResult) { alert(aResult); } }; var sl = Components.classes["@mozilla.org/network/stream-loader;1"] .createInstance(Components.interfaces.nsIStreamLoader); sl.init(channel, observer, null);
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. foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate foStream.write(data, data.length); foStream.close();
Flags parameter to the nsIFileOutputStream::init()
function
(For more information refer to prio.h file).
flags: The file status flags. It is a bitwise OR of the following bit flags (only one of the first three flags below may be used):
Name | Value | Description |
---|---|---|
PR_RDONLY | 0x01 | Open for reading only. |
PR_WRONLY | 0x02 | Open for writing only. |
PR_RDWR | 0x04 | Open for reading and writing. |
PR_CREATE_FILE | 0x08 |
If the file does not exist, the file is created. If the file exists, this flag has no effect. |
PR_APPEND | 0x10 |
The file pointer is set to the end of the file prior to each write. |
PR_TRUNCATE | 0x20 |
If the file exists, its length is truncated to 0. |
PR_SYNC | 0x40 |
If set, each write will wait for both the file data and file status to be physically updated. |
PR_EXCL | 0x80 |
With PR_CREATE_FILE, if the file does not exist, the file is created. If the file already exists, no action and NULL is returned. |