Visit Mozilla.org

Extraits de code:Fichiers E/S

Un article de MDC.

Cette page vient d'être traduite, mais elle a besoin d'un relecteur différent du traducteur. Pensez également à toujours vérifier le contenu avec sa toute dernière version en anglais.

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

Sommaire

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