Revision as of 23:24, 26 September 2006 Np (Talk | contribs) <-- Previous diff |
Revision as of 21:11, 7 November 2006 Grimholtz (Talk | contribs) 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 "native" 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/"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) | + | |
- | 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]] | + | |