Fragmenty kodu:Plik I/O
z Mozilla Developer Center, polskiego centrum programistów Mozilli.
UWAGA: Tłumaczenie tej strony nie zostało zakończone.
Może być ona niekompletna lub wymagać korekty.
Chcesz pomóc? | Dokończ tłumaczenie | Sprawdź ortografię | Więcej takich stron...
This article describes local file input/output in chrome JavaScript.
You access the file system using Mozilla XPCOM components. The list of components used for local I/O is available at XUL Planet.
[edytuj] Dostępne biblioteki
There are a few JavaScript wrappers for I/O XPCOM components. See JSLib and io.js (original by MonkeeSage). The io.js module is much smaller and very easy to use (simple examples are included in the module).
[edytuj] Tworzenie obiektu pliku (pliki "otwierające")
var file = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("/home");
UWAGA: 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.
UWAGA: initWithPath() / initWithFile() functions don't throw an exception if the specified file does not exist. An exception is thrown when methods that require the file existence are called, e.g. isDirectory(), moveTo(), etc.
[edytuj] Pobieranie specjalnych plików
// pobieranie katalogu profilu
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 | katalog profilu |
| 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) |
| ProfLD | Local Settings on windows; where the network cache and fastload files are stored |
| resource:app | application directory in a XULRunner app |
Look in the Source for other strings available: xpcom/io/nsDirectoryServiceDefs.h
, xpcom/io/nsAppDirectoryServiceDefs.h
.
[edytuj] Pobieranie swojego folderu rozszerzeń
UWAGA: 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 nsIExtensionManager like this:
const id = "ID";
var ext = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager)
.getInstallLocation(id)
.getItemLocation(id);
// ext is an instance of nsIFile, so ext.path contains the directory as a string
Replace ID with the extension's ID, and this will return an nsIFile of the directory of the extension . This value is read-only. For additional information, view the source: toolkit/mozapps/extensions/public/nsIExtensionManager.idl
.
In a JavaScript XPCOM component, you can also use the special __LOCATION__ variable as described here. It has been said this method is more reliable and works both with Firefox/Thunderbird 1.5+ and 1.0.
[edytuj] Tworzenie folderów
To create a folder, use nsIFile.create():
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 nsIFile.create reference.
[edytuj] Creating temporary files
To create a temporary file, use nsIFile.createUnique():
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);
[edytuj] User input via nsIFilePicker
The file picker component (nsIFilePicker) can be used to open standard Open / Save dialogs. The components returns user-specified file as nsIFile.
[edytuj] 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 XMLHttpRequest or nsIChannel (example).
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.
[edytuj] 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):
[edytuj] 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);
[edytuj] 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.
[edytuj] Navigating with nsIFile
[edytuj] 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.
[edytuj] Enumerating files in given directory
The snippet below makes an array of nsIFiles 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);
}
[edytuj] Reading from a file
NOTE: The sample code below does not handle text with non-ASCII characters. See Reading textual data details on how to read text from other character sets.
[edytuj] 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, 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);
[edytuj] 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);
[edytuj] 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);
[edytuj] Binary File
For instance, to get the data in a PNG file:
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var url = ios.newURI(aFileURL, null, null);
if (!url || !url.schemeIs("file")) throw "Expected a file URL.";
var pngFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
pngFile.initWithPath(url.path);
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
istream.init(pngFile, -1, -1, false);
var bstream = Components.classes["@mozilla.org/binaryinputstream;1"]
.createInstance(Components.interfaces.nsIBinaryInputStream);
bstream.setInputStream(istream);
var bytes = bstream.readBytes(bstream.available());
[edytuj] Writing to a file
NOTE: This code is not intl-aware. Writing non-ASCII characters will not work correctly. See Writing textual data for intl-aware code.
// 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. |
[edytuj] Writing a Binary File
For example, here we can write PNG data to a file.
// pngBinary already exists
var aFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
aFile.initWithPath( "/tmp/mypicture.png" );
aFile.createUnique( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 600);
var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
stream.init(aFile, 0x04 | 0x08 | 0x20, 664, 0); // write, create, truncate
stream.write(pngBinary, pngBinary.length);
if (stream instanceof Components.interfaces.nsISafeOutputStream) {
stream.finish();
} else {
stream.close();
}
[edytuj] More
There are more methods and properties on nsIFile and nsILocalFile interfaces, please refer to documentation on XUL Planet. Those methods/properties are mostly self-explanatory, so we haven't included examples of using them here.