MozillaZine

File IO

From MozillaZine Knowledge Base

(Difference between revisions)
Revision as of 23:24, 26 September 2006
Np (Talk | contribs)
(→nsIFile and path strings - update XHR link)
<-- Previous diff
Revision as of 21:11, 7 November 2006
Grimholtz (Talk | contribs)
(moved to MDC)
Next diff -->
Line 1: Line 1:
{{extdev}} {{extdev}}
- +Moved [http://developer.mozilla.org/en/docs/Code_snippets:File_I/O here].
-This article describes local file input/output in chrome JavaScript.+[[Category:Redirects]]
- +
-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==+
-There are a few JavaScript wrappers for I/O XPCOM components. See [http://jslib.mozdev.org/ JSLib] and [[io.js]] (original by [http://gratisdei.com/io.js MonkeeSage]). The io.js module is much smaller and very easy to use (simple examples are included in the module).+
- +
-==Creating a file object ("opening" files)==+
-<pre>+
-var file = Components.classes["@mozilla.org/file/local;1"]+
- .createInstance(Components.interfaces.nsILocalFile);+
-file.initWithPath("/home");+
-</pre>+
- +
-Note, that the path passed to <code>initWithPath()</code> should be in &quot;native&quot; form (e.g. <tt>"C:\\Windows"</tt>). If you need to use file:// URIs as initializers, see below.+
- +
-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==+
-<pre>+
-// get profile directory+
-var file = Components.classes["@mozilla.org/file/directory_service;1"]+
- .getService(Components.interfaces.nsIProperties)+
- .get("ProfD", Components.interfaces.nsIFile);+
-</pre>+
- +
-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"+
-! 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: [http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h] [http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h].+
- +
-===Getting your extension's folder===+
-: ''This will only work in Firefox/Thunderbird 1.5, not 1.0.''+
-To get the directory that an extension is installed in, you have to use <code>nsIExtensionManager</code> like this:+
- const id = "ID";+
- var ext = Components.classes["@mozilla.org/extensions/manager;1"]+
- .getService(Components.interfaces.nsIExtensionManager)+
- .getInstallLocation(id)+
- .getItemLocation(id); +
- +
-Replace ''ID'' with the extension's [http://developer.mozilla.org/en/docs/Install_Manifests#id ID], and this will return an <code>nsIFile</code> of the directory of the extension . This value is read only. For additional information, view the source [http://lxr.mozilla.org/mozilla1.8/source/toolkit/mozapps/extensions/public/nsIExtensionManager.idl#71].+
- +
-==Creating Folders==+
-To create a folder, use <code>nsIFile.create()</code>:+
- var file = Components.classes["@mozilla.org/file/directory_service;1"]+
- .getService(Components.interfaces.nsIProperties)+
- .get("ProfD", Components.interfaces.nsIFile);+
- file.append(''"DIR"'');+
- if( !file.exists() || !file.isDirectory() ) { // if it doesn't exist, create+
- file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0664);+
- }+
-The above example creates a folder called ''"DIR"'' in the [[Profile folder]]. For more information, refer to the [http://www.xulplanet.com/references/xpcomref/ifaces/nsIFile.html#method_create nsIFile Reference] at XULPlanet.+
- +
-==Creating temporary files==+
-To create a temporary file, use <code>nsIFile.createUnique()</code>:+
-<pre>+
-var file = Components.classes["@mozilla.org/file/directory_service;1"]+
- .getService(Components.interfaces.nsIProperties)+
- .get("TmpD", Components.interfaces.nsIFile);+
-file.append("suggestedName.tmp");+
-file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0664);+
-// do whatever you need to the created file+
-alert(file.path);+
-</pre>+
- +
-==User input via nsIFilePicker==+
-The [http://developer.mozilla.org/en/docs/nsIFilePicker file picker component (nsIFilePicker)] can be used to open standard Open / Save dialogs. The components returns user-specified file as nsIFile.+
- +
-==nsIFile and path strings==+
-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+
-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);+
-</pre>+
- +
-To load from ''file://'', ''http://'', ''chrome://'', ''resource://'' and other URLs directly, use [http://developer.mozilla.org/en/docs/XMLHttpRequest XMLHttpRequest] or [http://xulplanet.com/references/xpcomref/ifaces/nsIChannel.html nsIChannel] ([http://forums.mozillazine.org/viewtopic.php?p=921150#921150 example]).+
- +
-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==+
-The following two snippets show the right way to store a file path in user preferences ([[Dev : Using preferences|more about preferences in Mozilla]]):+
- +
-===Absolute path (nsILocalFile)===+
-To store arbitrary path in user preferences, use this code.+
-<pre>+
-// |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>+
- +
-===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:+
-<pre>+
-// 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>+
- +
-==Navigating with nsIFile==+
- +
-===Get a file in given directory===+
-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>+
-is possible, but <code>nsIFile::append()</code> 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 <code>|nsIFile|</code>s corresponding to sub-directories/&quot;sub-files&quot; 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)+
-var entries = file.directoryEntries;+
-var array = [];+
-while(entries.hasMoreElements())+
-{+
- var entry = entries.getNext();+
- entry.QueryInterface(Components.interfaces.nsIFile);+
- array.push(entry);+
-}+
-</pre>+
- +
-==Reading from a file==+
- +
-''Note'': This code is not intl-aware. Reading non-ASCII characters '''will not work correctly'''. See [http://developer.mozilla.org/en/docs/Reading_textual_data Reading textual data] for intl-aware code.+
- +
-===Simple===+
-<pre>// |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, 0);+
-sstream.init(fstream); +
- +
-var str = sstream.read(4096);+
-while (str.length > 0) {+
- data += str;+
- str = sstream.read(4096);+
-}+
- +
-sstream.close();+
-fstream.close();+
-alert(data);</pre>+
- +
-===Line by line===+
-<pre>+
-// 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>+
- +
-===Asynchronously===+
- +
-This will allow you to read a file without locking up the UI thread.+
- +
-<pre>// |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);+
-</pre>+
- +
-==Writing to a file==+
-''Note'': This code is not intl-aware. Writing non-ASCII characters '''will not work correctly'''. See [http://developer.mozilla.org/en/docs/Writing_textual_data Writing textual data] for intl-aware code.+
- +
-<pre>+
-// 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();+
-</pre>+
- +
-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]).+
- +
-'''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):+
-{| border="1" cellpadding="5" rules="all"+
-! 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.+
-|}+
- +
-==More==+
-There are more methods and properties on <code>nsIFile</code> and <code>nsILocalFile</code> interfaces, please refer to documentation on [http://xulplanet.com/references/xpcomref/group_Files.html XUL Planet]. Those methods/properties are mostly self-explanatory, so we haven't included examples of using them here.+
- +
-[[Category:Example code]] [[Category:XPCOM example code]] [[Category:JavaScript example code]]+

Revision as of 21:11, 7 November 2006

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).

Moved here.