Como capturar nenhum arquivo para fs.readFileSync ()?

135

No node.js, readFile () mostra como capturar um erro, no entanto, não há comentários para a função readFileSync () em relação à manipulação de erros. Sendo assim, se eu tentar usar o readFileSync () quando não houver arquivo, recebo o erro Error: ENOENT, no such file or directory.

Como capturar a exceção que está sendo lançada? O documento não declara quais exceções são lançadas, então não sei quais exceções preciso capturar. Devo observar que não gosto do estilo genérico de 'pegar todas as exceções possíveis' das instruções try / catch. Nesse caso, desejo capturar a exceção específica que ocorre quando o arquivo não existe e tento executar o readFileSync.

Observe que eu estou executando funções de sincronização apenas na inicialização antes de servir as tentativas de conexão, portanto, comentários que eu não deveria estar usando funções de sincronização não são necessários :-)

Metalskin
fonte
1
Você também pode usar fs.existsSync()como pode ser visto na minha nova resposta
Francisco Presencia

Respostas:

206

Basicamente, fs.readFileSyncgera um erro quando um arquivo não é encontrado. Este erro é do Errorprotótipo e lançado usando throw, portanto, a única maneira de capturar é com um try / catchbloco:

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
}

Infelizmente, você não pode detectar qual erro foi lançado apenas observando sua cadeia de protótipos:

if (err instanceof Error)

é o melhor que você pode fazer, e isso será verdade para a maioria (se não todos) dos erros. Por isso, sugiro que você vá com a codepropriedade e verifique seu valor:

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

Dessa forma, você lida apenas com esse erro específico e lança novamente todos os outros erros.

Como alternativa, você também pode acessar a messagepropriedade do erro para verificar a mensagem de erro detalhada, que neste caso é:

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

Espero que isto ajude.

Golo Roden
fonte
1
Obrigado, essa é a informação que eu estava procurando. Apenas presumi que seria um tipo específico de erro. Também acabei de perceber que não entendi como a tentativa / captura funciona. Estava pensando que era possível capturar um tipo de erro específico (à la java). Obrigado pela informação Golo. :-)
Metalskin 18/01
2
Também EACCEScódigo deve ser verificado na declaração se para o caso quando o arquivo está lá, mas não pode ser lido devido à falta de permissões
Gergely Toth
21

Eu prefiro essa maneira de lidar com isso. Você pode verificar se o arquivo existe de forma síncrona:

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: se o seu programa também excluir arquivos, isso terá uma condição de corrida, conforme observado nos comentários. Se, no entanto, você apenas escreve ou sobrescreve arquivos, sem excluí-los, isso é ótimo.

Francisco Presencia
fonte
2
agora, fs.existsSync não está mais obsoleto : "Observe que fs.exists () está obsoleto, mas fs.existsSync () não está."
21417 Falkodev
17
Não é nada melhor. E se o arquivo for removido do disco entre a chamada existSync e readFileSync? Seu código agora tem uma condição de corrida construído em espera de acontecer ...
tkarls
2
@tkarls sim, isso está totalmente certo, foi escrito em 2015 quando eu ainda estava aprendendo o Node.js e ele tem uma condição de corrida. No entanto, duas coisas a serem observadas: a semelhança dessa condição de corrida é tão mínima que ela pode basicamente ser ignorada, e a segunda e substituindo a primeira é que eu usaria try / catch com async / waiting hoje em dia, tornando meu código mais flexível para "outras" exceções (já que o Nó é compatível com exceções).
Francisco Presencia
1
As condições da corrida não importam até que importem. Respostas como essa são por que o software é tão cheio de bugs, por que você precisa reiniciar o computador com tanta frequência, por que existem tantas vulnerabilidades de segurança etc. etc. O Stack Overflow deve ter um sinalizador para respostas potencialmente prejudiciais.
Jonathan Tran
Outro comentário N anos depois, depois de aprender muito mais (acrescentou uma nota na resposta). Isso é totalmente bom no contexto de um programa de sistema de arquivos somente gravação, mas, como observado, se os arquivos também podem ser removidos, isso tem uma condição de corrida e não é um código que eu escreveria hoje em dia (especialmente por causa dessa sincronização!). Também criei o pacote filescom tudo o que tenho aprendido a tornar o assíncrono e o try / catch mais fácil.
Francisco Presencia 12/06
11

Você precisa capturar o erro e depois verificar que tipo de erro é esse.

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
fonte
... faça com que 'jogue errado';
drudru
Existe alguma maneira de capturar o mesmo erro com a versão não sincronizada da função?
Ki Jéy
1
@ KiJéy O código assíncrono transmite o erro como o primeiro argumento do retorno de chamada; portanto, se você verificar se obtém o mesmo comportamento.
Loganfsmyth 31/05/19
4

Eu uso um lambda chamado imediatamente para estes cenários:

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

async versão:

const config = await (async () => {
  try {
    return JSON.parse(await fs.readFileAsync('config.json'));
  } catch (error) {
    return {};
  }
})();
sdgfsdh
fonte
Você pode adicionar à sua postagem que sua solução é para o ECMAScript 6. Desde 01/01/18, não há suporte do IE com aproximadamente 77% de cobertura do uso do navegador ( caniuse.com/#feat=arrow-functions ). Estou curioso, como você atende aos usuários do IE?
Metalskin
2
@ Metalskin Webpack + Babel. No entanto, fsé um módulo Nó
sdgfsdh
Ahh, estou sem contato com o nó, suspeito que o nó não tenha suportado o ES6 quando fiz a pergunta (pode estar errado). Meio que esqueci esta era uma questão nó bem ;-)
Metalskin
atualizar isso ... fs.readFileAsync()agora fs.readFile() e também não deve colocar a função assíncrona dentro de uma tentativa / captura em node.js. o try / catch nunca receberá o erro, pois é assíncrono. em vez disso, transmita o erro no retorno de chamada e lida com ele: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); from: nodejs.org/dist/latest-v12.x/docs/api/…
KH B
Acredito que o try-catch será chamado se a promessa for rejeitada e você estiver aguardando a promessa.
sdgfsdh 30/03
0

Tente usar o Async para evitar o bloqueio do único thread que você possui com o NodeJS. Veja este exemplo:

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

Mais tarde, pode usar esta função assíncrona com try / catch de qualquer outra função:

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 codificação!

jdnichollsc
fonte
0

O mecanismo try… catch do JavaScript não pode ser usado para interceptar erros gerados por APIs assíncronas. Um erro comum para iniciantes é tentar usar throw dentro de um retorno de chamada com erro:

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

Isso não funcionará porque a função de retorno de chamada passada para fs.readFile () é chamada de forma assíncrona. Quando o retorno de chamada foi chamado, o código circundante, incluindo o bloco try ... catch, já havia saído. Lançar um erro dentro do retorno de chamada pode travar o processo Node.js. na maioria dos casos. Se os domínios estiverem ativados ou um manipulador tiver sido registrado com process.on ('uncaughtException'), esses erros poderão ser interceptados.

referência: https://nodejs.org/api/errors.html

ViktorKrpn
fonte