¿Cómo capturar ningún archivo para fs.readFileSync ()?

135

Dentro de node.js, readFile () muestra cómo capturar un error, sin embargo, no hay comentarios para la función readFileSync () con respecto al manejo de errores. Como tal, si intento usar readFileSync () cuando no hay ningún archivo, aparece el error Error: ENOENT, no such file or directory.

¿Cómo capturo la excepción que se lanza? El doco no indica qué excepciones se lanzan, por lo que no sé qué excepciones necesito atrapar. Debo señalar que no me gusta el estilo genérico de 'capturar todas las excepciones posibles' de las declaraciones try / catch. En este caso, deseo capturar la excepción específica que ocurre cuando el archivo no existe e intento realizar el readFileSync.

Tenga en cuenta que estoy realizando funciones de sincronización solo en el inicio antes de servir los intentos de conexión, por lo que no es necesario comentar que no debería usar las funciones de sincronización :-)

Piel de metal
fuente
1
También podría usar fs.existsSync()como se puede ver en mi nueva respuesta
Francisco Presencia,

Respuestas:

206

Básicamente, fs.readFileSyncarroja un error cuando no se encuentra un archivo. Este error proviene del Errorprototipo y se usa throw, por lo tanto, la única forma de atraparlo es con un try / catchbloque:

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
}

Desafortunadamente, no puede detectar qué error se ha lanzado simplemente mirando su cadena de prototipos:

if (err instanceof Error)

es lo mejor que puede hacer, y esto será cierto para la mayoría de los errores (si no todos). Por lo tanto, le sugiero que vaya con la codepropiedad y verifique su valor:

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

De esta manera, solo lidias con este error específico y vuelves a lanzar todos los demás errores.

Alternativamente, también puede acceder a la messagepropiedad del error para verificar el mensaje de error detallado, que en este caso es:

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

Espero que esto ayude.

Golo Roden
fuente
1
Gracias, esa es la información que estaba buscando. Supuse que sería un tipo específico de error. También me acabo de dar cuenta de que entendí mal cómo funciona el try / catch, estaba pensando que podría detectar un tipo de error específico (a la java). Gracias por la información Golo. :-)
Metalskin
2
También se EACCESdebe verificar el código en la declaración if para el caso cuando el archivo está allí pero no se puede leer debido a la falta de permisos
Gergely Toth
21

Prefiero esta forma de manejar esto. Puede verificar si el archivo existe sincrónicamente:

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

Nota: si su programa también elimina archivos, esto tiene una condición de carrera como se indica en los comentarios. Sin embargo, si solo escribe o sobrescribe archivos, sin eliminarlos, entonces esto está muy bien.

Francisco Presencia
fuente
2
ahora, fs.existsSync ya no está en desuso : "Tenga en cuenta que fs.exists () está en desuso, pero fs.existsSync () no".
falkodev
17
No mejor en absoluto. ¿Qué sucede si el archivo se elimina del disco entre la llamada existSync y readFileSync? El código tiene ahora una condición de carrera construida en punto de ocurrir ...
tkarls
2
@tkarls sí, eso es totalmente correcto, eso fue escrito en 2015 cuando todavía estaba aprendiendo Node.js y tiene una condición de carrera. Sin embargo, hay dos cosas a tener en cuenta: la similitud de esta condición de carrera es tan mínima que básicamente se puede ignorar, y la segunda y la primera es que estaría usando try / catch con async / wait hoy en día haciendo que mi código sea más flexible para "otras" excepciones (ya que Node es amigable con las excepciones).
Francisco Presencia
1
Las condiciones de carrera no importan hasta que lo hagan. Respuestas como esta son por qué el software está tan lleno de errores, por qué necesita reiniciar su computadora con tanta frecuencia, por qué hay tantas vulnerabilidades de seguridad, etc., etc.
Jonathan Tran
Otro comentario N años después, después de aprender un montón más (agregó una nota en la respuesta). Esto está totalmente bien en el contexto de un programa de sistema de archivos de solo escritura, pero como se señaló si los archivos también se pueden eliminar, esto tiene una condición de carrera y no es el código que escribiría hoy en día (¡especialmente por esa sincronización!). También escribí el paquete filescon todo lo que he estado aprendiendo para hacer que la sincronización y el intento / captura sean más fáciles.
Francisco Presencia
11

Debe detectar el error y luego verificar qué tipo de error es.

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
fuente
... haz que 'lanzar err;'
drudru
¿Hay alguna forma de detectar ese mismo error con la versión no sincronizada de la función?
Ki Jéy
1
El código @ KiJéy Async pasa el error como el primer argumento de la devolución de llamada, por lo que si verifica que obtendría el mismo comportamiento.
loganfsmyth
4

Utilizo una lambda invocada inmediatamente para estos escenarios:

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

async versión:

const config = await (async () => {
  try {
    return JSON.parse(await fs.readFileAsync('config.json'));
  } catch (error) {
    return {};
  }
})();
sdgfsdh
fuente
Es posible que desee agregar a su publicación que su solución es para ECMAScript 6. A partir del 01/01/18 no hay soporte de IE con aproximadamente el 77% de cobertura del uso del navegador ( caniuse.com/#feat=arrow-functions ). Tengo curiosidad, ¿cómo atender a los usuarios de IE?
Metalskin
2
@Metalskin Webpack + Babel. Sin embargo, fses un módulo Node
sdgfsdh
Ahh, estoy fuera de contacto con el nodo, sospecho que ese nodo no era compatible con ES6 cuando hice la pregunta (podría estar equivocado). Un poco olvidé que esta también era una pregunta de nodo ;-)
Metalskin el
actualizar esto ... fs.readFileAsync()es ahora fs.readFile() y tampoco debería poner la función asíncrona dentro de un try / catch en node.js. el try / catch nunca recibirá el error ya que es asíncrono. en su lugar, pase el error en la devolución de llamada y maneje allí: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); desde: nodejs.org/dist/latest-v12.x/docs/api/…
KH B
Creo que se llamará al try-catch si se rechaza la promesa y usted la está esperando.
sdgfsdh
0

Intente usar Async en su lugar para evitar bloquear el único hilo que tiene con NodeJS. Mira este ejemplo:

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

Más tarde puede usar esta función asincrónica con try / catch desde cualquier otra función:

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

¡Feliz codificación!

jdnichollsc
fuente
0

El mecanismo JavaScript try ... catch no puede utilizarse para interceptar errores generados por API asincrónicas. Un error común para los principiantes es intentar usar throw dentro de una devolución de llamada de primer error:

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

Esto no funcionará porque la función de devolución de llamada pasada a fs.readFile () se llama de forma asincrónica. Para cuando se haya llamado la devolución de llamada, el código circundante, incluido el bloque try ... catch, ya habrá salido. Lanzar un error dentro de la devolución de llamada puede bloquear el proceso Node.js en la mayoría de los casos. Si los dominios están habilitados, o se ha registrado un controlador con process.on ('uncaughtException'), dichos errores pueden ser interceptados.

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

ViktorKrpn
fuente