|
|
(2 intermediate revisions by one other user not shown) |
Line 1: |
Line 1: |
| {{extdev}}
| | Moved [https://developer.mozilla.org/en/Code_snippets:File_I/O] (MDC). |
| | | [[Category:Redirects]] |
| 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 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]]
| |