Як зафіксувати жоден файл для fs.readFileSync ()?


135

У node.js readFile () показує, як зафіксувати помилку, проте немає коментарів щодо функції readFileSync () щодо обробки помилок. Якщо я намагаюся використовувати readFileSync (), коли файлу немає, я отримую помилку Error: ENOENT, no such file or directory.

Як зафіксувати викид, що викидається? У doco не вказано, які винятки кинуті, тому я не знаю, які винятки мені потрібно знайти. Я мушу зазначити, що мені не подобається загальний стиль "ловити кожен можливий виняток" у стилі операцій "try / catch". У цьому випадку я хочу знайти певний виняток, який виникає, коли файл не існує, і я намагаюся виконати readFileSync.

Зауважте, що я виконую функції синхронізації лише під час запуску перед подачею спроб з'єднання, тому коментарі, які я не повинен використовувати функції синхронізації, не потрібні :-)


1
Ви також fs.existsSync()можете використати те , що можна побачити в моїй новій відповіді
Francisco Presencia

Відповіді:


206

В основному, fs.readFileSyncвидає помилку, коли файл не знайдений. Ця помилка походить від Errorпрототипу і викидається за допомогою throw, тому єдиний спосіб зловити - це try / catchблок:

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
}

На жаль, ви не можете виявити, яка помилка була викинута, просто переглянувши її прототип:

if (err instanceof Error)

це найкраще, що ви можете зробити, і це буде справедливо для більшості (якщо не всіх) помилок. Тому я б запропонував вам піти з codeвласністю та перевірити його вартість:

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

Таким чином, ви маєте справу лише з цією конкретною помилкою та перекидаєте всі інші помилки.

Крім того, ви також можете отримати доступ до messageвластивості помилки, щоб перевірити детальне повідомлення про помилку, яке в цьому випадку:

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

Сподіваюся, це допомагає.


1
Дякую, це інформація, яку я шукав. Я просто припускав, що це буде конкретний тип Помилки. Я також щойно зрозумів, що я неправильно зрозумів, як працює спроба / улов, я думав, що ви можете впіймати певний тип помилки (a la java). Дякую за інформацію Голо. :-)
Metalskin

2
Також EACCESкод слід перевірити в операторі if, якщо файл є, але його неможливо прочитати через відсутність дозволів
Гергелі Тот

21

Я вважаю за краще такий спосіб поводження з цим. Ви можете перевірити, чи файл існує синхронно:

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

Примітка: якщо ваша програма також видаляє файли, це стан перегонів, як зазначено в коментарях. Якщо ви лише пишете або переписуєте файли, не видаляючи їх, то це абсолютно добре.


2
тепер fs.existsSync більше не застаріло : "Зауважте, що fs.exists () застаріле, але fs.existsSync () - ні."
falkodev

17
Зовсім не краще. Що робити, якщо файл вилучено з диска між викликом съществуваSync та readFileSync? Зараз у вашому коді створена умова гонки, яка чекає, коли станеться ...
tkarls

2
@tkarls так, це абсолютно правильно, це було написано в 2015 році, коли я ще навчався Node.js, і він має перегони. Однак слід зазначити дві речі: ймовірність цього стану гонки настільки мінімальна, що її в основному можна ігнорувати, а друге і перевершує перше - це те, що я б зараз використовував спробу / ловити з асинхронізуванням / очікувати, що зараз зробить мій код більш гнучким до "інші" винятки (оскільки Node сприятливий для винятків).
Francisco Presencia

1
Умови перегонів не мають значення, поки вони не стануть. Такі відповіді - це те, чому програмне забезпечення настільки заблоковано, чому потрібно так часто перезавантажувати комп’ютер, чому так багато вразливих місць безпеки і т. Д. І т.д. Стік Overflow повинен містити прапор для потенційно шкідливих відповідей.
Джонатан Тран

Ще один коментар через N років, дізнавшись ще купу (додав примітку у відповіді). Це абсолютно добре в контексті програми файлової системи, що використовується лише для запису, але, як зазначалося, якщо файли також можна видалити, це стан перегонів, і це не код, який я б писав сьогодні (спеціально через синхронізацію!). Я також автор пакету filesз усім, чого я навчився робити асинхронізацію та спробувати / зловити простіше.
Francisco Presencia

11

Ви повинні зловити помилку, а потім перевірити, що це за помилка.

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
}

... зробіть це "киньте помилку;"
друдру

Чи є спосіб виявити ту саму помилку з несинхронізованою версією функції?
Кі Джей

1
@ KiJéy Async код передає помилку як перший аргумент зворотного дзвінка, тож якщо ви перевіряєте, що у вас буде така ж поведінка.
loganfsmyth

4

Я використовую негайно викликану лямбда для цих сценаріїв:

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

async версія:

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

Ви можете додати до своєї публікації, що ваше рішення призначено для ECMAScript 6. На 01.01.18 IE не підтримує IE з покриттям використання браузера приблизно на 77% ( caniuse.com/#feat=arrow-functions ). Мені цікаво, як ви обслуговуєте користувачів IE?
Metalskin

2
@Metalskin Webpack + Babel. Однак fsє модуль Node
sdgfsdh

Ага, я не зв’язуюся з вузлом, я підозрюю, що вузол не підтримував ES6, коли я задавав питання (може бути неправильним). Ніби не забув, що це питання про вузол ;-)
Metalskin

оновлення цього ... fs.readFileAsync()зараз, fs.readFile() а також не повинно ставити функцію async всередині спробувати / catch у node.js. спробувати / catch ніколи не отримає помилку, оскільки це асинхроніка. замість цього передайте помилку у зворотному дзвінку та обробіть її там: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); з: nodejs.org/dist/latest-v12.x/docs/api/…
KH B

Я вірю, що спроба лову буде зателефонована, якщо обіцянку буде відхилено, і ви чекаєте на обіцянку.
sdgfsdh

0

Спробуйте використовувати Async замість цього, щоб уникнути блокування єдиного потоку, який ви маєте з NodeJS. Перевірте цей приклад:

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

Пізніше можна використовувати цю функцію асинхронізації за допомогою try / catch з будь-якої іншої функції:

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

Щасливе кодування!


0

Механізм спробувати JavaScript catch… не може використовуватися для перехоплення помилок, створених асинхронними API. Поширена помилка для початківців полягає в тому, щоб спробувати використати кидок всередині зворотного виклику першого помилки:

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

Це не буде працювати, оскільки функція зворотного виклику, передана fs.readFile (), викликається асинхронно. До моменту виклику зворотного дзвінка навколишній код, включаючи блок спробу… catch, вже вийшов. Введення помилки всередині зворотного дзвінка може призвести до краху процесу Node.js у більшості випадків. Якщо домени ввімкнено або обробник зареєстрований у process.on ('uncaughtException'), такі помилки можуть бути перехоплені.

довідка: https://nodejs.org/api/errors.html

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.