如何不为fs.readFileSync()捕获文件?


135

在node.js中,readFile()显示了如何捕获错误,但是对于readFileSync()函数,关于错误处理没有任何注释。这样,如果我在没有文件的情况下尝试使用readFileSync(),则会收到错误消息Error: ENOENT, no such file or directory

我如何捕获抛出的异常?Doco没有说明抛出了什么异常,所以我不知道需要捕获哪些异常。我应该注意,我不喜欢普通的“捕获每个可能的异常”样式的try / catch语句。在这种情况下,我希望捕获当文件不存在并且尝试执行readFileSync时发生的特定异常。

请注意,在执行连接尝试之前,我仅在启动时执行同步功能,因此不需要我不应该使用同步功能的注释:-)


1
你也可以使用fs.existsSync()如中可以看到我的新的答案
旧金山Presencia

Answers:


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的工作原理,我以为您可以捕获特定的错误类型(java类)。感谢您的信息Golo。:-)
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
一点也不好。如果在existSync和readFileSync调用之间从磁盘上删除文件怎么办?您的代码现在已经内置了等待发生的竞争条件...
tkarls

2
@tkarls是的,这是完全正确的,那是在2015年我还在学习Node.js时编写的,它具有竞争条件。但是,有两点需要注意:这种竞争条件的可能性很小,以至于基本上可以忽略不计;第二种是超级种子,第一种是我现在将try / catch与async / await结合使用,从而使我的代码更灵活地“其他”异常(因为Node是友好的异常)。
弗朗西斯科·普雷森西亚'17

1
比赛条件无关紧要。诸如此类的答案是为什么软件如此漏洞百出,为什么您需要如此频繁地重启计算机,为什么有那么多的安全漏洞等,等等。StackOverflow应该有一个标志来标识潜在的有害答案。
Jonathan Tran

N年后,在学习了更多内容之后又发表了另一条评论(在答案中添加了注释)。在只写文件系统程序的上下文中,这是完全可以的,但是要注意的是,如果还可以删除文件,则将导致竞争,并且这不是我现在要编写的代码(特别是由于该Sync!)。我还files用我一直在学习的所有内容编写了该软件包,以简化异步和尝试/捕获。
弗朗西斯科·普雷森西亚

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
}

...使那个“抛出错误;”
drudru

有没有办法使用该函数的非同步版本来捕获相同的错误?
基耶(KiJéy)'18年

1
@KiJéy异步代码将错误作为回调的第一个参数传递,因此,如果您检查是否会得到相同的行为。
loganfsmyth

4

对于以下情况,我使用立即调用的lambda:

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 '18年

2
@Metalskin Webpack + Babel。但是,这fs是一个节点模块
sdgfsdh

啊,我与节点失去联系,我怀疑当我问这个问题时节点不支持ES6(可能是错误的)。Kinda忘记了这也是一个节点问题;-)
Metalskin

更新此... fs.readFileAsync()现在fs.readFile() 并且也不应将异步功能放在node.js的try / catch中。try / catch永远不会收到错误,因为它是异步的。而不是通过错误的回调和处理它还有:fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); 来自:nodejs.org/dist/latest-v12.x/​​docs/api/...
KH乙

我相信,如果诺言被拒绝,而您正在等待诺言,就会调用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;
}

以后可以将此异步功能与其他任何功能的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 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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.