Wie erfasse ich keine Datei für fs.readFileSync ()?

135

In node.js zeigt readFile () , wie ein Fehler erfasst wird. Es gibt jedoch keinen Kommentar für die Funktion readFileSync () zur Fehlerbehandlung. Wenn ich versuche, readFileSync () zu verwenden, wenn keine Datei vorhanden ist, wird der Fehler angezeigt Error: ENOENT, no such file or directory.

Wie erfasse ich die ausgelöste Ausnahme? Das Dokument gibt nicht an, welche Ausnahmen ausgelöst werden, daher weiß ich nicht, welche Ausnahmen ich abfangen muss. Ich sollte beachten, dass ich den generischen Stil "try jede einzelne Ausnahme fangen" von try / catch-Anweisungen nicht mag. In diesem Fall möchte ich die spezifische Ausnahme abfangen, die auftritt, wenn die Datei nicht vorhanden ist, und ich versuche, readFileSync auszuführen.

Bitte beachten Sie, dass ich Synchronisierungsfunktionen nur beim Start ausführe, bevor Verbindungsversuche ausgeführt werden. Daher sind keine Kommentare erforderlich, dass ich keine Synchronisierungsfunktionen verwenden sollte :-)

Metallhaut
quelle
1
Sie können auch verwenden, fs.existsSync()wie in meiner neuen Antwort
Francisco Presencia

Antworten:

206

Grundsätzlich wird fs.readFileSyncein Fehler ausgegeben, wenn eine Datei nicht gefunden wird. Dieser Fehler stammt vom ErrorPrototyp und wird mit ausgelöst throw. Daher kann nur mit einem try / catchBlock abgefangen werden:

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
}

Leider können Sie nicht erkennen, welcher Fehler ausgelöst wurde, wenn Sie sich nur die Prototypenkette ansehen:

if (err instanceof Error)

ist das Beste, was Sie tun können, und dies gilt für die meisten (wenn nicht alle) Fehler. Daher würde ich vorschlagen, dass Sie mit der codeImmobilie gehen und ihren Wert überprüfen:

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

Auf diese Weise behandeln Sie nur diesen spezifischen Fehler und werfen alle anderen Fehler erneut.

Alternativ können Sie auch auf die messageEigenschaft des Fehlers zugreifen , um die detaillierte Fehlermeldung zu überprüfen. In diesem Fall lautet dies:

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

Hoffe das hilft.

Golo Roden
quelle
1
Danke, das ist die Information, nach der ich gesucht habe. Ich habe nur angenommen, dass es sich um eine bestimmte Art von Fehler handelt. Ich habe auch gerade festgestellt, dass ich falsch verstanden habe, wie das Ausprobieren funktioniert. Ich dachte, Sie könnten einen bestimmten Fehlertyp (a la Java) abfangen. Danke für die Info Golo. :-)
Metalskin
2
Auch EACCESCode sollte in der if-Anweisung für den Fall überprüft werden, dass die Datei vorhanden ist, aber aufgrund fehlender Berechtigungen nicht gelesen werden kann
Gergely Toth
21

Ich bevorzuge diese Art, damit umzugehen. Sie können überprüfen, ob die Datei synchron vorhanden ist:

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');
}

Hinweis: Wenn Ihr Programm auch Dateien löscht, hat dies eine Race-Bedingung, wie in den Kommentaren angegeben. Wenn Sie jedoch nur Dateien schreiben oder überschreiben, ohne sie zu löschen, ist dies völlig in Ordnung.

Francisco Presencia
quelle
2
Jetzt ist fs.existsSync nicht mehr veraltet : "Beachten Sie, dass fs.exists () veraltet ist, fs.existsSync () jedoch nicht."
Falkodev
17
Gar nicht besser. Was passiert, wenn die Datei zwischen dem Aufruf existSync und readFileSync von der Festplatte entfernt wird? Ihr Code hat jetzt eine Rennbedingung eingebaut, die darauf wartet, passiert zu werden ...
tkarls
2
@tkarls ja das ist völlig richtig, das wurde 2015 geschrieben, als ich noch Node.js lernte und es hat eine Rennbedingung. Zwei Dinge, die zu beachten sind: Die Ähnlichkeit dieser Rennbedingung ist so gering, dass sie im Grunde genommen ignoriert werden kann, und die zweite und die erste ist, dass ich heutzutage try / catch mit async / await verwenden würde, um meinen Code flexibler zu machen "andere" Ausnahmen (da Node ausnahmefreundlich ist).
Francisco Presencia
1
Die Rennbedingungen spielen keine Rolle, bis sie es tun. Antworten wie diese sind, warum Software so fehlerbehaftet ist, warum Sie Ihren Computer so oft neu starten müssen, warum es so viele Sicherheitslücken gibt usw. usw. Der Stapelüberlauf sollte ein Flag für potenziell schädliche Antworten haben.
Jonathan Tran
Ein weiterer Kommentar N Jahre später, nachdem ich ein paar mehr gelernt hatte (eine Anmerkung in der Antwort hinzugefügt). Dies ist im Kontext eines Nur-Schreib-Dateisystemprogramms völlig in Ordnung, aber wie bereits erwähnt, hat dies eine Race-Bedingung, wenn die Dateien auch entfernt werden können, und es ist kein Code, den ich heutzutage schreiben würde (speziell wegen dieser Synchronisierung!). Ich habe das Paket auch filesmit allem verfasst, was ich gelernt habe, um das Asynchronisieren und Ausprobieren zu vereinfachen.
Francisco Presencia
11

Sie müssen den Fehler abfangen und dann überprüfen, um welche Art von Fehler es sich handelt.

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
quelle
... machen Sie das "werfen irren;"
Drudru
Gibt es eine Möglichkeit, denselben Fehler mit der nicht synchronisierten Version der Funktion abzufangen?
Ki Jéy
1
@ KiJéy Async-Code übergibt den Fehler als erstes Argument des Rückrufs. Wenn Sie also überprüfen, ob Sie dasselbe Verhalten erhalten.
Loganfsmyth
4

Ich verwende ein sofort aufgerufenes Lambda für diese Szenarien:

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

async Ausführung:

const config = await (async () => {
  try {
    return JSON.parse(await fs.readFileAsync('config.json'));
  } catch (error) {
    return {};
  }
})();
sdgfsdh
quelle
Möglicherweise möchten Sie Ihrem Beitrag hinzufügen, dass Ihre Lösung für ECMAScript 6 ist. Ab dem 01.01.18 gibt es keine Unterstützung durch den IE mit einer Abdeckung der Browsernutzung von ca. 77% ( caniuse.com/#feat=arrow-functions ). Ich bin neugierig, wie können Sie IE-Benutzer bedienen?
Metalskin
2
@ Metalskin Webpack + Babel. Allerdings fsist ein
Knotenmodul
Ahh, ich habe keinen Kontakt zum Knoten. Ich vermute, dass der Knoten ES6 nicht unterstützt hat, als ich die Frage gestellt habe (könnte falsch sein). Ein bisschen vergessen, dass dies auch eine
Knotenfrage war ;-)
Das Aktualisieren dieses ... fs.readFileAsync()ist jetzt fs.readFile() und sollte auch die asynchrone Funktion nicht in einen try / catch in node.js einfügen. Der Versuch / Fang wird niemals den Fehler erhalten, da er asynchron ist. Übergeben Sie stattdessen den Fehler im Rückruf und behandeln Sie ihn dort: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); von: nodejs.org/dist/latest-v12.x/docs/api/…
KH B
Ich glaube, dass der Try-Catch aufgerufen wird, wenn das Versprechen abgelehnt wird und Sie auf das Versprechen warten.
sdgfsdh
0

Versuchen Sie stattdessen, Async zu verwenden, um zu vermeiden, dass der einzige Thread blockiert wird, den Sie mit NodeJS haben. Überprüfen Sie dieses Beispiel:

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;
}

Später kann diese asynchrone Funktion mit try / catch von jeder anderen Funktion verwendet werden:

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
  }
}

Viel Spaß beim Codieren!

jdnichollsc
quelle
0

Der JavaScript-Mechanismus try… catch kann nicht zum Abfangen von Fehlern verwendet werden, die von asynchronen APIs generiert werden. Ein häufiger Fehler für Anfänger besteht darin, zu versuchen, throw in einem Fehler-First-Callback zu verwenden:

// 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);
}

Dies funktioniert nicht, da die an fs.readFile () übergebene Rückruffunktion asynchron aufgerufen wird. Zu dem Zeitpunkt, an dem der Rückruf aufgerufen wurde, ist der umgebende Code, einschließlich des try… catch-Blocks, bereits beendet. Das Auslösen eines Fehlers innerhalb des Rückrufs kann in den meisten Fällen den Node.js-Prozess zum Absturz bringen. Wenn Domänen aktiviert sind oder ein Handler bei process.on registriert wurde ('uncaughtException'), können solche Fehler abgefangen werden.

Referenz: https://nodejs.org/api/errors.html

ViktorKrpn
quelle