Node a un ensemble d'API de flux de données qui peut traiter des fichiers comme le traitement des flux de réseau, ce qui est très pratique à utiliser, mais il permet uniquement d'être traités de manière séquentielle et ne peut pas lire et écrire des fichiers au hasard. Par conséquent, certaines opérations de système de fichiers sous-jacentes doivent être utilisées.
Ce chapitre couvre les bases du traitement des fichiers, y compris comment ouvrir un fichier, lire une partie d'un fichier, écrire des données et fermer un fichier.
De nombreuses API de fichier de Node sont presque une réplique de l'API de fichier correspondant dans UNIX (POSIX). Par exemple, la façon d'utiliser des descripteurs de fichiers est utilisée. Tout comme dans Unix, le descripteur de fichier est également un numéro entier dans le nœud, représentant l'index d'une entité dans la table des descripteurs de fichiers de processus.
Il existe 3 descripteurs de fichiers spéciaux - 1, 2 et 3. Ils représentent respectivement les entrées standard, la sortie standard et le descripteur de fichier d'erreur standard. L'entrée standard, comme son nom l'indique, est un flux en lecture seule, que les processus utilisent pour lire les données de la console ou du canal de processus. La sortie standard et les erreurs standard sont des descripteurs de fichiers utilisés uniquement pour la sortie des données. Ils sont souvent utilisés pour produire des données sur les consoles, d'autres processus ou fichiers. Les erreurs standard sont responsables de la sortie du message d'erreur, tandis que la sortie standard est responsable de la sortie de processus ordinaire.
Une fois le processus démarré, ces descripteurs de fichiers peuvent être utilisés et ils n'ont pas réellement de fichiers physiques correspondants. Vous ne pouvez pas lire et écrire des données à un emplacement aléatoire. (Remarque du traducteur: Le texte d'origine est que vous pouvez écrire et lire à partir de positions spécifiques dans le fichier. Selon le contexte, l'auteur peut avoir écrit moins "non"), et ne peut lire et sortir en séquence comme les flux de données du réseau d'exploitation, et les données écrites ne peuvent pas être modifiées.
Les fichiers ordinaires ne sont pas soumis à cette limitation. Par exemple, dans Node, vous pouvez créer des fichiers qui ne peuvent ajouter que des données à la queue, et vous pouvez également créer des fichiers qui lisent et écrivent des emplacements aléatoires.
Presque toutes les opérations liées au fichier impliquent le traitement des chemins de fichier. Ce chapitre introduira d'abord ces fonctions d'outil, puis expliquera les opérations de lecture, d'écriture et de données approfondies.
Chemin de fichier de processus
Les chemins de fichier sont divisés en deux types: chemins relatifs et chemins absolus, et ils sont utilisés pour représenter des fichiers spécifiques. Vous pouvez fusionner des chemins de fichier, extraire les informations de nom de fichier et même détecter si le fichier existe.
Dans Node, vous pouvez utiliser des chaînes pour manipuler les chemins de fichier, mais cela compliquera le problème. Par exemple, vous souhaitez connecter différentes parties du chemin, certaines parties se terminent avec "/" mais certaines ne le font pas, et le séparateur de chemin peut également être différent dans différents systèmes d'exploitation, donc lorsque vous les connectez, le code sera très verbeux et gênant.
Heureusement, Node a un module appelé chemin qui peut vous aider à standardiser, à connecter, à analyser les chemins, à vous convertir des chemins absolus en chemins relatifs, à extraire diverses parties d'informations à partir des chemins et à détecter si le fichier existe. En général, le module Path est en fait juste un traitement de chaîne, et il n'ira pas au système de fichiers pour la vérification (exception de la fonction Path.exists).
Standardisation des chemins
Les normaliser avant de stocker ou d'utiliser des chemins est généralement une bonne idée. Par exemple, les chemins de fichier obtenus par les fichiers d'entrée ou de configuration de l'utilisateur, ou chemins connectés par deux chemins ou plus, doivent généralement être standardisés. Un chemin peut être normalisé en utilisant la fonction de normalisation du module de chemin, et il peut également gérer "..", "." // ". Par exemple:
La copie de code est la suivante:
var path = require ('path');
path.normalize ('/ foo / bar // baz / asdf / quux / ..');
// => '/ foo / bar / baz / asdf'
Chemin de connexion
En utilisant la fonction path.join (), vous pouvez concaténer autant de chaînes de chemin. Vous pouvez simplement passer toutes les chaînes de chemin à la fonction join () en séquence:
La copie de code est la suivante:
var path = require ('path');
path.join ('/ foo', 'bar', 'baz / asdf', 'quux', '..');
// => '/ foo / bar / baz / asdf'
Comme vous pouvez le voir, Path.Join () normalisera automatiquement le chemin à l'intérieur.
Chemin
Utilisez Path.Resolve () pour résoudre plusieurs chemins dans un chemin absolu. Sa fonction est comme les opérations "CD" une par une sur ces chemins. Contrairement aux paramètres de la commande CD, ces chemins peuvent être des fichiers et ils n'ont pas à exister dans la vie réelle - la méthode Path.Resolve () n'accétera pas au système de fichiers sous-jacent pour déterminer si le chemin existe, ce n'est que quelques opérations de chaîne.
Par exemple:
La copie de code est la suivante:
var path = require ('path');
path.resolve ('/ foo / bar', './baz');
// => / foo / bar / baz
path.resolve ('/ foo / bar', '/ tmp / file /');
// => / tmp / fichier
Si le résultat d'analyse n'est pas un chemin absolu, Path.Resolve () ajoutera le répertoire de travail actuel comme chemin vers le résultat d'analyse, par exemple:
La copie de code est la suivante:
path.resolve ('wwwroot', 'static_files / png /', '../gif/image.gif');
// Si le répertoire de travail actuel est / home / moi-même / nœud, il reviendra
// => /home/myself/node/wwwroot/static_files/gif/image.gif '
Calculez les chemins relatifs de deux chemins absolus
path.relative () peut vous dire si vous passez d'une adresse absolue à une autre adresse absolue, par exemple:
La copie de code est la suivante:
var path = require ('path');
path.relative ('/ data / orandea / test / aaa', '/ data / orandea / impl / bbb');
// => ../../impl/bbb
Extraire les données du chemin
Prenez le chemin "/foo/bar/myfile.txt" comme exemple. Si vous souhaitez obtenir tout le contenu du répertoire parent (/ foo / bar), ou lisez d'autres fichiers du même répertoire de niveau, pour cela, vous devez utiliser Path.Dirname (filepath) pour obtenir la partie du répertoire du chemin de fichier, tel que:
La copie de code est la suivante:
var path = require ('path');
path.dirname ('/ foo / bar / baz / asdf / quux.txt');
// => / foo / bar / baz / asdf
Ou, si vous souhaitez obtenir le nom de fichier à partir du chemin du fichier, c'est-à-dire la dernière partie du chemin de fichier, vous pouvez utiliser la fonction path.basename:
La copie de code est la suivante:
var path = require ('path');
path.basename ('/ foo / bar / baz / asdf / quux.html')
// => quux.html
Le chemin de fichier peut également contenir une extension de fichier, généralement la partie de la chaîne après le dernier "." caractère dans le nom du fichier.
path.basename peut également accepter une chaîne de nom d'extension comme deuxième paramètre, de sorte que le nom du fichier renvoyé supprime automatiquement l'extension et renvoie uniquement la partie du nom du fichier:
La copie de code est la suivante:
var path = require ('path');
path.basename ('/ foo / bar / baz / asdf / quux.html', '.html');
// => quux
Pour ce faire, vous devez d'abord connaître l'extension du fichier. Vous pouvez utiliser Path.ExtName () pour obtenir l'extension:
La copie de code est la suivante:
var path = require ('path');
path.ExtName ('/ a / b / index.html');
// => '.html'
path.ExtName ('/ a / bc / index');
// => ''
path.ExtName ('/ a / bc /.');
// => ''
path.ExtName ('/ a / bc / d.');
// => '.'
Vérifiez si le chemin existe
Jusqu'à présent, les opérations de traitement du chemin mentionnées ci-dessus n'ont rien à voir avec le système de fichiers sous-jacent, mais ne sont que quelques opérations de chaîne. Cependant, vous devez parfois déterminer s'il existe un chemin de fichier. Par exemple, vous devez parfois déterminer si un fichier ou un répertoire existe. S'il n'existe pas, vous pouvez utiliser Path.exsits ():
La copie de code est la suivante:
var path = require ('path');
path.exists ('/ etc / passwd', fonction (existe) {
console.log ('existe:', existe);
// => true
});
path.exists ('/ do_not_exist', function (existant) {
console.log ('existe:', existe);
// => false
});
Remarque: À partir de la version Node0.8, existe, est déplacé du module de chemin vers le module FS et est devenu Fs.existes. Sauf pour l'espace de noms, rien d'autre n'a changé:
La copie de code est la suivante:
var fs = require ('fs');
fs.exists ('/ do ise_not_exist', fonction (existant) {
console.log ('existe:', existe);
// => false
});
Path.exists () est une opération d'E / S. Parce qu'il est asynchrone, une fonction de rappel est requise. Lorsque l'opération d'E / S revient, la fonction de rappel est appelée et le résultat lui est transmis. Vous pouvez également utiliser sa version synchrone de Path.existSync (), qui a la même fonction, sauf qu'elle n'appelle pas la fonction de rappel, mais renvoie directement le résultat:
La copie de code est la suivante:
var path = require ('path');
path.existSync ('/ etc / passwd');
// => true
Introduction au module FS
Le module FS contient toutes les fonctions connexes pour la requête et le traitement de fichiers. À l'aide de ces fonctions, vous pouvez interroger les informations du fichier, lire, écrire et fermer des fichiers. Importez le module FS comme ceci:
La copie de code est la suivante:
var fs = require ('fs')
Informations sur le fichier de requête
Parfois, vous devrez peut-être connaître des informations de fichier telles que la taille du fichier, la date de création ou les autorisations. Vous pouvez utiliser la fonction Fs.stath pour interroger les méta-informations d'un fichier ou d'un répertoire:
La copie de code est la suivante:
var fs = require ('fs');
fsat ('/ etc / passwd', fonction (err, statts) {
if (err) {lancer err;}
console.log (statistiques);
});
Cet extrait de code aura une sortie similaire à ce qui suit
La copie de code est la suivante:
{dev: 234881026,
INO: 95028917,
Mode: 33188,
nlink: 1,
uid: 0,
GID: 0,
rdev: 0,
Taille: 5086,
BlkSize: 4096,
Blocs: 0,
Atime: ven, 18 novembre 2011 22:44:47 GMT,
mtime: jeu, 08 septembre 2011 23:50:04 GMT,
Ctime: Thu, 08 septembre 2011 23:50:04 GMT}
1. L'appel Fsat () passera une instance de la classe Statts en tant que paramètre à sa fonction de rappel. Vous pouvez utiliser l'instance de statistiques comme ce qui suit:
2.stats.isfile () - Renvoie vrai s'il s'agit d'un fichier standard, pas d'un répertoire, d'une prise, d'un lien symbolique ou d'un appareil, sinon faux
3.stats.isDiretory () - S'il s'agit d'un répertoire, renvoyez mar, sinon faux
4.stats.isblockDevice () - Retour True s'il s'agit d'un périphérique de bloc. Dans la plupart des systèmes UNIX, le périphérique de bloc est généralement dans le répertoire / dev.
5.stats.ischracterDevice () - Renvoie vrai s'il s'agit d'un appareil de caractère
6.stats.issymbolicklink () - renvoie true s'il s'agit d'un lien de fichier
7.stats.isisfo () - S'il s'agit d'un FIFO (un type spécial d'Unix nommé Pipe) renvoie True
8.stats.issocket () - S'il s'agit d'une prise Unix (todo: googe it)
Ouvrir le fichier
Avant de lire ou de traiter un fichier, vous devez d'abord utiliser la fonction Fs.Open pour ouvrir le fichier, puis la fonction de rappel que vous fournissez sera appelée et obtiendra le descripteur du fichier. Plus tard, vous pouvez utiliser ce descripteur de fichier pour lire et écrire le fichier ouvert:
La copie de code est la suivante:
var fs = require ('fs');
fs.open ('/ path / to / file', 'r', fonction (err, fd) {
// a un descripteur de fichiers FD
});
Le premier paramètre de Fs.open est le chemin du fichier, et le deuxième paramètre est quelques balises utilisées pour indiquer dans quel mode le fichier est ouvert. Ces balises peuvent être R, R +, W, W +, A ou A +. Vous trouverez ci-dessous une explication de ces balises (à partir de la page FOPEN de la documentation UNIX)
1.R - Ouvrez le fichier en mode en lecture seule, l'emplacement initial du flux de données commence au fichier
2.R + - Ouvrez le fichier d'une manière lisible et écrite, et l'emplacement initial du flux de données commence au fichier
3.W - Si le fichier existe, effacez la longueur du fichier de 0, c'est-à-dire que le contenu du fichier sera perdu. S'il n'existe pas, essayez de le créer. L'emplacement initial du flux de données commence au fichier
4.W + - Ouvrez le fichier d'une manière lisible et écrite. Si le fichier n'existe pas, essayez de le créer. Si le fichier existe, effacez la longueur du fichier de 0, c'est-à-dire que le contenu du fichier sera perdu. L'emplacement initial du flux de données commence au fichier
5.A - Ouvrez le fichier de manière en écriture uniquement. Si le fichier n'existe pas, essayez de le créer. L'emplacement initial du flux de données est à la fin du fichier. Chaque opération d'écriture ultérieure ajoute les données à l'arrière du fichier.
6.A + - Ouvrez le fichier d'une manière lisible et écrite. Si le fichier n'existe pas, essayez de le créer. L'emplacement initial du flux de données est à la fin du fichier. Chaque opération d'écriture suivante ajoutera les données à l'arrière du fichier.
Lire le fichier
Une fois le fichier ouvert, vous pouvez commencer à lire le contenu du fichier, mais avant de commencer, vous devez créer un tampon pour placer les données. Cet objet tampon sera transmis à la fonction FS.Read comme un paramètre et sera rempli de données par Fs.Read.
La copie de code est la suivante:
var fs = require ('fs');
fs.open ('./ my_file.txt', 'r', fonction ouverte (err, fd) {
if (err) {lancer err}
var readbuffer = nouveau tampon (1024),
tamperoffset = 0,
bufferLength = readbuffer.length,
FilePosition = 100;
fs.read (fd,
readbuffer,
tamperoffset,
BufferLength,
Fileposition,
fonction lecture (err, readBytes) {
if (err) {throw err; }
Console.log ('Just Read' + ReadBytes + 'octets');
if (readBytes> 0) {
console.log (readbuffer.slice (0, readBytes));
}
});
});
Le code ci-dessus essaie d'ouvrir un fichier. Après l'ouverture avec succès (appelant la fonction ouverte), il commence à demander à lire les 1024 octets suivants des données du 100e octet du flux de fichiers (ligne 11).
Le dernier paramètre de fs.read () est une fonction de rappel (ligne 16). Lorsque les trois situations suivantes se produisent, on l'appellera:
1. Une erreur s'est produite
2. Les données ont été lues avec succès
3. Aucune donnée à lire
Si une erreur se produit, le premier paramètre (ERR) fournira la fonction de rappel avec un objet contenant le message d'erreur, sinon ce paramètre est nul. Si les données sont lues avec succès, le deuxième paramètre (ReadBytes) indiquera la taille des données lues dans le tampon. Si la valeur est 0, cela signifie que la fin du fichier a été atteinte.
Remarque: Une fois l'objet tampon transmis à fs.open (), le contrôle de l'objet tampon est transféré à la commande de lecture. Ce n'est que lorsque la fonction de rappel est appelée le contrôle de l'objet tampon vous sera renvoyé. Donc, avant cela, ne lisez pas et n'écrivez pas ou ne laissez pas d'autres appels de fonction utiliser cet objet tampon; Sinon, vous pouvez lire des données incomplètes et, pire, vous pouvez écrire des données dans cet objet tampon simultanément.
Écrire un fichier
Passez un objet tampon contenant des données en les passant à fs.write () et écrivez des données dans un fichier ouvert:
La copie de code est la suivante:
var fs = require ('fs');
fs.open ('./ my_file.txt', 'a', fonction ouverte (err, fd) {
if (err) {throw err; }
var writebuffer = new tamper ('écrire cette chaîne'),
BufferPosition = 0,
BufferLength = WriteBuffer.Length, FileSposition = NULL;
Fs.Write (FD,
writebuffer,
BufferPosition,
BufferLength,
Fileposition,
function write (err, écrit) {
if (err) {throw err; }
Console.log («écrit» + écrit + «octets»);
});
});
Dans cet exemple, la deuxième ligne de code tente d'ouvrir un fichier en mode annexe (a), puis la septième ligne de code (Note du traducteur: le texte d'origine est 9) écrit des données dans le fichier. L'objet tampon doit être accompagné de plusieurs informations sous forme de paramètres:
1. Données de tampon
2. Où les données à écrire commencent-elles dans le tampon
3. La durée des données à écrire
4. Où rédiger les données dans le fichier
5. La fonction de rappel appelée une fois l'opération terminée écrite
Dans cet exemple, le paramètre FilePostion est nul, ce qui signifie que la fonction d'écriture écrira les données à l'emplacement actuel du pointeur de fichier. Parce qu'il s'agit d'un fichier ouvert en mode annexe, le pointeur de fichier est à la fin du fichier.
Comme les opérations de lecture, n'utilisez pas quel objet tampon entrant est utilisé pendant l'exécution de Fs.Write. Une fois que Fs.Write commence à s'exécuter, il prend le contrôle de cet objet tampon. Vous ne pouvez qu'attendre que la fonction de rappel soit appelée avant de la réutiliser.
Fermez le fichier
Vous avez peut-être remarqué que jusqu'à présent, tous les exemples de ce chapitre n'ont pas de code pour fermer le fichier. Parce qu'ils ne sont que de petits et simples exemples lorsqu'ils sont utilisés une seule fois, le système d'exploitation garantit que tous les fichiers sont fermés lorsque le processus de nœud se termine.
Cependant, dans l'application réelle, une fois un fichier ouvert, vous souhaitez vous assurer de finir par le fermer. Pour ce faire, vous devez tracer tous ces descripteurs de fichiers ouverts, puis appeler fs.close (fd [, rappel]) lorsqu'ils ne sont plus habitués à les fermer éventuellement. Si vous ne faites pas attention, il est facile de manquer un certain descripteur de fichiers. L'exemple suivant fournit une fonction appelée OpenandWriteToSystemLog, qui montre comment fermer soigneusement les fichiers:
La copie de code est la suivante:
var fs = require ('fs');
fonction openandWriteToSystemLog (writeBuffer, callback) {
fs.open ('./ my_file', 'a', fonction ouverte (err, fd) {
if (err) {return callback (err); }
fonction notifyerror (err) {
fs.close (fd, function () {
rappel (err);
});
}
var tamperoffset = 0,
bufferLength = writeBuffer.length,
fileposition = null;
Fs.Write (FD, WriteBuffer, BufferOffset, BufferLength, FileSposition,
function write (err, écrit) {
if (err) {return notifyerror (err); }
fs.close (fd, function () {
rappel (err);
});
}
));
});
}
openandWriteTosystemlog (
Nouveau tampon («Écriture de cette chaîne»),
fonction fait (err) {
if (err) {
console.log ("Erreur lors de l'ouverture et de l'écriture:", err.Message);
retour;
}
console.log («tout fait sans erreurs»);
}
));
Ici, une fonction appelée OpenAndWriteToSystemlog est fournie, qui accepte un objet tampon contenant les données à écrire, et une fonction de rappel appelée une fois l'opération terminée ou une erreur se produit. Si une erreur se produit, le premier paramètre de la fonction de rappel contiendra cet objet d'erreur.
Notez que la fonction interne NotifyError, qui ferme le fichier et rapporte une erreur qui se produit.
Remarque: Jusque-là, vous savez comment utiliser les opérations atomiques sous-jacentes pour ouvrir, lire, écrire et fermer des fichiers. Cependant, Node a également un ensemble de constructeurs plus avancés qui vous permettent de traiter les fichiers de manière plus simple.
Par exemple, vous souhaitez utiliser un moyen sûr d'autoriser deux ou plusieurs opérations d'écriture pour ajouter des données dans un fichier simultanément, et vous pouvez utiliser WriteStream.
De plus, si vous souhaitez lire une certaine zone d'un fichier, vous pouvez envisager d'utiliser ReadStream. Ces deux cas d'utilisation seront introduits dans le chapitre 9 "La lecture et la rédaction du streaming des données".
résumé
Lorsque vous utilisez un fichier, vous devez traiter et extraire des informations de chemin de fichier dans la plupart des cas. En utilisant le module de chemin, vous pouvez connecter des chemins, standardiser les chemins, calculer les différences de chemin et convertir les chemins relatifs en chemins absolus. Vous pouvez extraire des composants de chemin tels que des extensions, des noms de fichiers, des répertoires, etc.
Node fournit un ensemble d'API sous-jacent dans le module FS pour accéder au système de fichiers, et l'API sous-jacente utilise des descripteurs de fichiers pour manipuler des fichiers. Vous pouvez ouvrir le fichier avec fs.open, écrire le fichier avec fs.write, lire le fichier avec fs.read et fermer le fichier avec fs.close.
Lorsqu'une erreur se produit, vous devez toujours utiliser la logique de traitement d'erreur correcte pour fermer le fichier - pour vous assurer que ces descripteurs de fichiers ouvrir sont fermés avant le retour de l'appel.