Comment capturer aucun fichier pour fs.readFileSync ()?

135

Dans node.js readFile () montre comment capturer une erreur, cependant il n'y a pas de commentaire pour la fonction readFileSync () concernant la gestion des erreurs. En tant que tel, si j'essaye d'utiliser readFileSync () quand il n'y a pas de fichier, j'obtiens l'erreur Error: ENOENT, no such file or directory.

Comment capturer l'exception levée? Le doco n'indique pas quelles exceptions sont levées, donc je ne sais pas quelles exceptions je dois attraper. Je dois noter que je n'aime pas le style générique «attraper toutes les exceptions possibles» des instructions try / catch. Dans ce cas, je souhaite attraper l'exception spécifique qui se produit lorsque le fichier n'existe pas et que j'essaye d'effectuer le readFileSync.

Veuillez noter que j'effectue des fonctions de synchronisation uniquement au démarrage avant de servir les tentatives de connexion, donc les commentaires indiquant que je ne devrais pas utiliser les fonctions de synchronisation ne sont pas obligatoires :-)

Metalskin
la source
1
Vous pouvez également utiliser fs.existsSync()comme on peut le voir dans ma nouvelle réponse
Francisco Presencia

Réponses:

206

Fondamentalement, fs.readFileSyncgénère une erreur lorsqu'un fichier n'est pas trouvé. Cette erreur provient du Errorprototype et est lancée à l'aide throw, par conséquent, le seul moyen d'attraper est avec un try / catchbloc:

var fileContents;
try {
  fileContents = fs.readFileSync('foo.bar');
} catch (err) {
  // Here you get the error when the file was not found,
  // but you also get any other error
}

Malheureusement, vous ne pouvez pas détecter quelle erreur a été générée simplement en regardant sa chaîne de prototypes:

if (err instanceof Error)

est le mieux que vous puissiez faire, et ce sera vrai pour la plupart (sinon toutes) des erreurs. Par conséquent, je vous suggère d'aller avec la codepropriété et de vérifier sa valeur:

if (err.code === 'ENOENT') {
  console.log('File not found!');
} else {
  throw err;
}

De cette façon, vous traitez uniquement cette erreur spécifique et relancez toutes les autres erreurs.

Vous pouvez également accéder à la messagepropriété de l'erreur pour vérifier le message d'erreur détaillé, qui dans ce cas est:

ENOENT, no such file or directory 'foo.bar'

J'espère que cela t'aides.

Golo Roden
la source
1
Merci, c'est l'information que je recherchais. J'ai juste supposé que ce serait un type d'erreur spécifique. Je viens également de réaliser que j'ai mal compris comment fonctionne le try / catch, je pensais que vous pouviez attraper un type d'erreur spécifique (à la java). Merci pour l'info Golo. :-)
Metalskin
2
Le EACCEScode doit également être vérifié dans l'instruction if pour le cas où le fichier est là mais ne peut pas être lu en raison d'un manque d'autorisations
Gergely Toth
21

Je préfère cette façon de gérer cela. Vous pouvez vérifier si le fichier existe de manière synchrone:

var file = 'info.json';
var content = '';

// Check that the file exists locally
if(!fs.existsSync(file)) {
  console.log("File not found");
}

// The file *does* exist
else {
  // Read the file and do anything you want
  content = fs.readFileSync(file, 'utf-8');
}

Remarque: si votre programme supprime également des fichiers, cela a une condition de concurrence comme indiqué dans les commentaires. Si toutefois vous n'écrivez ou écrasez que des fichiers, sans les supprimer, alors c'est très bien.

Francisco Presencia
la source
2
maintenant, fs.existsSync n'est plus obsolète : "Notez que fs.exists () est obsolète, mais que fs.existsSync () ne l'est pas."
falkodev
17
Pas mieux du tout. Que faire si le fichier est supprimé du disque entre les appels existSync et readFileSync? Votre code a maintenant une condition de
concurrence
2
@tkarls oui c'est tout à fait vrai, cela a été écrit en 2015 alors que j'apprenais encore Node.js et il a une condition de course. Cependant, deux choses à noter: la vraisemblance de cette condition de concurrence est si minime qu'elle peut être ignorée, et la seconde et remplacer la première est que j'utiliserais try / catch avec async / await de nos jours, ce qui rend mon code plus flexible pour "autres" exceptions (puisque Node est compatible avec les exceptions).
Francisco Presencia
1
Les conditions de course n'ont pas d'importance tant qu'elles ne le font pas. Des réponses comme celle-ci expliquent pourquoi les logiciels sont si pleins de bogues, pourquoi vous devez redémarrer votre ordinateur si souvent, pourquoi il y a tant de vulnérabilités de sécurité, etc., etc. Stack Overflow devrait avoir un indicateur pour les réponses potentiellement nuisibles.
Jonathan Tran le
Un autre commentaire N ans plus tard, après avoir appris un tas de plus (ajouté une note dans la réponse). C'est tout à fait correct dans le contexte d'un programme de système de fichiers en écriture seule, mais comme indiqué, si les fichiers peuvent également être supprimés, cela a une condition de concurrence et ce n'est pas du code que j'écrirais de nos jours (spécialement à cause de cette synchronisation!). J'ai également créé le package filesavec tout ce que j'ai appris pour faciliter l'async et essayer / attraper.
Francisco Presencia
11

Vous devez attraper l'erreur, puis vérifier de quel type d'erreur il s'agit.

try {
  var data = fs.readFileSync(...)
} catch (err) {
  // If the type is not what you want, then just throw the error again.
  if (err.code !== 'ENOENT') throw err;

  // Handle a file-not-found error
}
loganfsmyth
la source
... faites que 'jeter err;'
drudru
Existe-t-il un moyen d'attraper la même erreur avec la version non synchronisée de la fonction?
Ki Jéy
1
@ Le code KiJéy Async transmet l'erreur comme premier argument du rappel, donc si vous vérifiez que vous obtenez le même comportement.
loganfsmyth
4

J'utilise un lambda immédiatement appelé pour ces scénarios:

const config = (() => {
  try {
    return JSON.parse(fs.readFileSync('config.json'));
  } catch (error) {
    return {};
  }
})();

async version:

const config = await (async () => {
  try {
    return JSON.parse(await fs.readFileAsync('config.json'));
  } catch (error) {
    return {};
  }
})();
sdgfsdh
la source
Vous voudrez peut-être ajouter à votre message que votre solution est pour ECMAScript 6. Depuis le 01/01/18, il n'y a pas de support d'IE avec une couverture d'environ 77% de l'utilisation du navigateur ( caniuse.com/#feat=arrow-functions ). Je suis curieux, comment répondez-vous aux utilisateurs d'IE?
Metalskin
2
@Metalskin Webpack + Babel. Cependant, fsest un module Node
sdgfsdh
Ahh, je ne suis pas en contact avec le nœud, je soupçonne que le nœud ne supportait pas ES6 lorsque j'ai posé la question (cela pourrait être faux). Kinda oublié que c'était une question de nœud aussi ;-)
Metalskin
mettre à jour ceci ... fs.readFileAsync()est maintenant fs.readFile() et ne devrait pas non plus mettre la fonction async à l'intérieur d'un try / catch dans node.js. le try / catch n'obtiendra jamais l'erreur car il est asynchrone. à la place, passez l'erreur dans le rappel et gérez-la ici: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); de: nodejs.org/dist/latest-v12.x/docs/api
KH B
Je crois que le try-catch sera appelé si la promesse est rejetée et que vous attendez la promesse.
sdgfsdh
0

Essayez plutôt d' utiliser Async pour éviter de bloquer le seul thread que vous avez avec NodeJS. Vérifiez cet exemple:

const util = require('util');
const fs = require('fs');
const path = require('path');
const readFileAsync = util.promisify(fs.readFile);

const readContentFile = async (filePath) => {
  // Eureka, you are using good code practices here!
  const content = await readFileAsync(path.join(__dirname, filePath), {
    encoding: 'utf8'
  })
  return content;
}

Plus tard, vous pouvez utiliser cette fonction asynchrone avec try / catch depuis n'importe quelle autre fonction:

const anyOtherFun = async () => {
  try {
    const fileContent = await readContentFile('my-file.txt');
  } catch (err) {
    // Here you get the error when the file was not found,
    // but you also get any other error
  }
}

Bon codage!

jdnichollsc
la source
0

Le mécanisme JavaScript try… catch ne peut pas être utilisé pour intercepter les erreurs générées par les API asynchrones. Une erreur courante pour les débutants est d'essayer d'utiliser throw dans un rappel d'erreur en premier:

// THIS WILL NOT WORK:
const fs = require('fs');

try {
  fs.readFile('/some/file/that/does-not-exist', (err, data) => {
    // Mistaken assumption: throwing here...
    if (err) {
      throw err;
    }
  });
} catch (err) {
  // This will not catch the throw!
  console.error(err);
}

Cela ne fonctionnera pas car la fonction de rappel passée à fs.readFile () est appelée de manière asynchrone. Au moment où le rappel a été appelé, le code environnant, y compris le bloc try… catch, sera déjà sorti. Lancer une erreur dans le rappel peut faire planter le processus Node.js dans la plupart des cas. Si les domaines sont activés ou si un gestionnaire a été enregistré avec process.on ('uncaughtException'), ces erreurs peuvent être interceptées.

référence: https://nodejs.org/api/errors.html

ViktorKrpn
la source