Extraits de code:Fichiers E/S
Un article de MDC.
Cet article décrit les accès entrée/sortie des fichiers locaux dans le chrome JavaScript.
Le système de fichiers est accessible en utilisant des composants XPCOM Mozilla. La liste des composants servant aux accès entrée/sortie locaux sont disponibles sur XUL Planet (en).
[modifier] Bibliothèques disponibles
Il existe quelques bibliothèques gérant des composants E/S XPCOM. Consultez la JSLib et io.js (version originale de MonkeeSage). Le module io.js est bien plus petit et simple à utiliser (de courts exemples sont inclus dans ce module).
[modifier] Création d'un objet fichier (« ouverture » de fichiers)
var file = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("/home");
Notez que le chemin passé à la fonction initWithPath() doit être écrit dans la forme « native » du système (par ex. "C:\\Windows"). Si vous devez utilisez des URI file://, voir ci-dessous.
Notez également que les fonctions initWithPath() / initWithFile() ne créent pas d'exception si un fichier spécifié n'existe pas. Une exception est créée lorsque des méthodes nécessitant l'existence du fichier sont appelées, comme par exemple isDirectory(), moveTo(), etc.
[modifier] Récupération de fichiers spéciaux
// récupérer le répertoire profil
var file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
Vous pouvez remplacer "ProfD" par l'une des chaînes de caractères suivantes (volées dans les commentaires du module E/S de MonkeeSage) :
| Chaîne | Description |
|---|---|
| ProfD | répertoire profil |
| DefProfRt | répertoire utilisateur (par ex., /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 (habituellement) |
| Home | racine de l'OS (par ex., /root) |
| TmpD | répertoire tmp de l'OS (par ex., /tmp) |
Vous trouverez d'autres chaînes dans le code source : xpcom/io/nsDirectoryServiceDefs.h, xpcom/io/nsAppDirectoryServiceDefs.h.
[modifier] Récupération du répertoire de votre extension
- Ceci ne fonctionnera que sous Firefox/Thunderbird 1.5+, pas sous 1.0.
Vous récupérez le répertoire où une extension est installée avec nsIExtensionManager comme ceci :
const id = "ID";
var ext = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager)
.getInstallLocation(id)
.getItemLocation(id);
Remplacez ID avec l'ID de l'extension pour obtenir un nsIFile du répertoire de l'extension. Cette valeur est en lecture seule. Pour plus d'information, voir toolkit/mozapps/extensions/public/nsIExtensionManager.idl.
[modifier] Création de répertoires
Pour créer un répertoire, utilisez 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() ) { // S'il n'existe pas, le créer
file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0664);
}
Cet exemple crée un répertoire appelé "DIR" dans le répertoire profil. Pour plus d'information, consultez la référence nsIFile.create.
[modifier] Création de fichiers temporaires
Pour créer un fichier temporaire, utilisez 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);
// utilisez le fichier créé
alert(file.path);
[modifier] Sélection par l'utilisateur via nsIFilePicker
Le composant de sélection de fichier (nsIFilePicker) sert à ouvrir une boîte de dialogue système d'ouverture ou de sauvegarde de fichiers. Il retourne un nsIFile désignant le fichier spécifié par l'utilisateur.
[modifier] nsIFile et chemin d'accès
La propriété nsIFile.path vous permet d'obtenir le chemin d'accès au fichier dans un format propre à votre plateforme, par ex. "C:\Windows\System32" ou "/usr/share".
Si vous souhaitez obtenir une URL file:// d'un fichier, ou un nsIFile à partir d'une URL file://, vous devez utilisez nsIFileProtocolHandler :
// file est un 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);
Pour lire un fichier directement depuis file://, http://, chrome://, resource:// et d'autres URL, utilisez XMLHttpRequest ou nsIChannel (exemple (en)).
Notez également que généralement, vous n'avez pas besoin de vous servir de nsIFile::path. Utilisez nsIFile directement quand c'est possible. Vous verrez ci-après un exemple de sauvegarde d'un chemin d'accès dans les préférences de l'utilisateur.
[modifier] Sauvegarde de nsILocalFile dans les préférences de l'utilisateur
Les deux extraits suivants montrent la méthode correcte pour sauvegarder le chemin d'accès d'un fichier dans les préférences de l'utilisateur (plus de précisions sur les préférences dans Mozilla (en)):
[modifier] Chemin d'accès absolu (nsILocalFile)
Pour sauvegarder un chemin d'accès absolu dans les préférences de l'utilisateur, utilisez le code suivant :
// |file| est un nsILocalFile
// 1. Écriture du chemin dans les préférences
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
.getBranch("extensions.myext.");
prefs.setComplexValue("nomfichier", Components.interfaces.nsILocalFile, file);
// 2. Lecture du chemin depuis les préférences
var file = prefs.getComplexValue("nomfichier", Components.interfaces.nsILocalFile);
[modifier] Chemin d'accès relatif (nsIRelativeFilePref)
Pour sauvegarder des chemins d'accès relatif à l'un des répertoires prédéfinis listés ci-dessus, par exemple relatif au répertoire profil, utilisez le code suivant :
// 1. Écriture dans les préférences
var relFile = Components.classes["@mozilla.org/pref-relativefile;1"]
.createInstance(Components.interfaces.nsIRelativeFilePref);
relFile.relativeToKey = "ProfD"; // ou une autre chaîne listée ci-dessus
relFile.file = file; // |file| est un nsILocalFile
prefs.setComplexValue("nomfichier",
Components.interfaces.nsIRelativeFilePref, relFile);
// 2. Lecture depuis les préférences
var value = prefs.getComplexValue("nomfichier",
Components.interfaces.nsIRelativeFilePref);
// |value.file| est le fichier.
[modifier] Manipulation avec nsIFile
[modifier] Récupération d'un fichier dans un répertoire donné
Admettons que file est un nsIFile pointant vers un répertoire (par ex. le répertoire du profil utilisateur). Vous pouvez utiliser file.append("myfile.txt"); pour que file pointe vers le fichier myfile.txt de ce répertoire.
Note : évitez d'utiliser la syntaxe dir.path+"\\"+"myfile.txt" car elle n'est pas inter-plateformes. L'utilisation de la syntaxe ((path.search(/\\/) != -1) ? path + "\\" : path + "/") + "myfile.txt"; est possible, mais nsIFile.append() est bien plus simple à lire et fonctionnera sur toutes les plateformes que supporte Mozilla.
[modifier] Liste des fichiers d'un répertoire
L'extrait suivant crée un tableau de nsIFile des sous-répertoires/fichiers d'un répertoire donné. Vous pouvez distinguer les fichiers des répertoires en appelant les méthodes nsIFile.isDirectory() et nsIFile.isFile() pour chaque entrée.
// file est le répertoire (nsIFile)
var entries = file.directoryEntries;
var array = [];
while(entries.hasMoreElements())
{
var entry = entries.getNext();
entry.QueryInterface(Components.interfaces.nsIFile);
array.push(entry);
}
[modifier] Lecture d'un fichier
Note : Ce code n'est pas internationalisable . La lecture de caractères non ASCII ne fonctionnera pas correctement. Consultez Lecture de données textuelles pour du code internationalisable.
[modifier] Simple
// |file| est un 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);
[modifier] Ligne par ligne
// ouvrir un flux entrant depuis le fichier
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);
// lire les lignes dans un tableau
var line = {}, lines = [], hasmore;
do {
hasmore = istream.readLine(line);
lines.push(line.value);
} while(hasmore);
istream.close();
// traitement des données lues
alert(lines);
[modifier] De manière asynchrone
Cet exemple vous permet de lire un fichier sans que l'interface utilisateur soit figée.
// |file| est un 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);
[modifier] Écriture dans un fichier
Note : Ce code n'est pas internationalisable . L'écriture de caractères non ASCII ne fonctionnera pas correctement. Consultez Écriture de données textuelles pour du code internationalisable.
// file est un nsIFile, data est une chaîne de caractères
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
// utiliser 0x02 | 0x10 pour ouvrir le fichier en ajout.
foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // écrire, créer, tronquer
foStream.write(data, data.length);
foStream.close();
Placez les bonnes options en paramètres de la fonction nsIFileOutputStream::init() (pour plus d'information, consultez prio.h file).
options : les options des états du fichier. Il s'agit d'une combinaison logique OU des options binaires suivantes (une seules des trois premières options peut être utilisée) :
| Nom | Valeur | Description |
|---|---|---|
| PR_RDONLY | 0x01 | Ouvrir en lecture seule. |
| PR_WRONLY | 0x02 | Ouvrir en écriture seule. |
| PR_RDWR | 0x04 | Ouvrir en lecture et écriture. |
| PR_CREATE_FILE | 0x08 |
Si le fichier n'existe pas, il sera créé. Si le fichier existe, cette option est sans effet. |
| PR_APPEND | 0x10 |
Le pointeur du fichier est placé à la fin de fichier avec chaque écriture. |
| PR_TRUNCATE | 0x20 |
Si le fichier existe, sa longueur est tronquée à 0. |
| PR_SYNC | 0x40 |
Si elle est définie, chaque écriture attendra que les données et les statuts du fichier soient physiquement mis à jour. |
| PR_EXCL | 0x80 |
Comme PR_CREATE_FILE, si le fichier n'existe pas, il est créé. Si le fichier existe déjà, aucune action n'est réalisée et NULL est retournée. |
[modifier] Informations complémentaires
Les interfaces nsIFile et nsILocalFile gèrent bien d'autres méthodes et propriétés. Consultez la documentation sur XUL Planet (en). La plupart de ces méthodes et propriétés sont suffisamment explicites pour être comprises sans devoir ajouter des exemples ici.