Как сохранить файл без файла для fs.readFileSync ()?

135

В node.js readFile () показывает, как зафиксировать ошибку, однако для функции readFileSync () нет комментариев относительно обработки ошибок. Таким образом, если я попытаюсь использовать readFileSync () при отсутствии файла, я получаю сообщение об ошибке Error: ENOENT, no such file or directory.

Как зафиксировать возникшее исключение? Документ не указывает, какие исключения выбрасываются, поэтому я не знаю, какие исключения мне нужно перехватить. Я должен отметить, что мне не нравится общий стиль операторов try / catch «поймать каждое возможное исключение». В этом случае я хочу поймать конкретное исключение, которое возникает, когда файл не существует, и я пытаюсь выполнить readFileSync.

Обратите внимание, что я выполняю функции синхронизации только при запуске, прежде чем обслуживать попытки подключения, поэтому комментарии о том, что мне не следует использовать функции синхронизации, не требуются :-)

MetalSkin
источник
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
Спасибо, это та информация, которую я искал. Я просто предположил, что это будет определенный тип ошибки. Я также только что понял, что неправильно понял, как работает try / catch, я думал, что вы можете поймать определенный тип ошибки (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
Совсем не лучше. Что, если файл будет удален с диска между вызовами existsSync и readFileSync? В вашем коде теперь встроено условие гонки, ожидающее
своего наступления
2
@tkarls да, это совершенно верно, это было написано в 2015 году, когда я все еще изучал Node.js, и у него есть состояние гонки. Однако следует отметить две вещи: вероятность этого состояния гонки настолько минимальна, что ее можно практически игнорировать, а второе, заменяющее первое, заключается в том, что в настоящее время я бы использовал try / catch с async / await, делая мой код более гибким для «прочие» исключения (поскольку Node дружественен к исключениям).
Francisco Presencia
1
Условия гонки не имеют значения, пока они не станут. Подобные ответы объясняют, почему в программном обеспечении так много ошибок, почему вам нужно так часто перезагружать компьютер, почему существует так много уязвимостей безопасности и т. Д. И т. Д. Stack Overflow должен иметь отметку для потенциально опасных ответов.
Джонатан Тран,
Еще один комментарий спустя N лет, после того, как узнал еще много (добавил примечание в ответ). Это совершенно нормально в контексте программы файловой системы только для записи, но, как уже отмечалось, если файлы также могут быть удалены, это имеет состояние гонки, и это не код, который я буду писать сейчас (особенно из-за этой Sync!). Я также написал пакет 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
}
loganfsmyth
источник
... сделайте это "бросить ошибку";
drudru
Есть ли способ отловить ту же ошибку с несинхронизированной версией функции?
Ki Jéy
1
Асинхронный код @ KiJéy передает ошибку в качестве первого аргумента обратного вызова, поэтому, если вы проверите, вы получите такое же поведение.
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 {};
  }
})();
sdgfsdh
источник
Вы можете добавить в свой пост, что ваше решение предназначено для ECMAScript 6. По состоянию на 01.01.18 нет поддержки IE с примерно 77% охватом использования браузера ( caniuse.com/#feat=arrow-functions ). Мне любопытно, как вы обслуживаете пользователей IE?
Metalskin 03
2
@Metalskin Webpack + Babel. Однако fsэто модуль узла
sdgfsdh 03
Ах, я потерял связь с узлом, я подозреваю, что узел не поддерживает ES6, когда я задал вопрос (может ошибаться). Как будто забыл, что это тоже был вопрос об узлах ;-)
Metalskin
обновление this ... fs.readFileAsync()сейчас fs.readFile() и также не должно помещать функцию async внутри try / catch в node.js. try / catch никогда не получит ошибку, поскольку он асинхронный. вместо этого передайте ошибку в обратном вызове и обрабатывайте ее там: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); from: nodejs.org/dist/latest-v12.x/docs/api/…
KH B
Я считаю, что try-catch будет вызываться, если обещание будет отклонено, а вы ожидаете его.
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;
}

Позже можно использовать эту асинхронную функцию с попыткой / уловом из любой другой функции:

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

Удачного кодирования!

jdnichollsc
источник
0

Механизм JavaScript try… catch не может использоваться для перехвата ошибок, генерируемых асинхронными API. Распространенной ошибкой новичков является попытка использовать throw внутри обратного вызова с ошибкой:

// 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 (), вызывается асинхронно. К тому времени, как обратный вызов будет вызван, окружающий код, включая блок try… catch, уже завершится. Сообщение об ошибке внутри обратного вызова в большинстве случаев может привести к сбою процесса Node.js. Если домены включены или обработчик был зарегистрирован в process.on ('uncaughtException'), такие ошибки можно перехватить.

ссылка: https://nodejs.org/api/errors.html

ViktorKrpn
источник