Visit Mozilla.org

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.

Spis treści

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