如何为 fs.readFileSync() 捕获没有文件?
Posted
技术标签:
【中文标题】如何为 fs.readFileSync() 捕获没有文件?【英文标题】:How to capture no file for fs.readFileSync()? 【发布时间】:2013-01-01 17:40:27 【问题描述】:在 node.js 中readFile() 显示了如何捕获错误,但是没有关于错误处理的readFileSync() 函数的注释。因此,如果我在没有文件的情况下尝试使用 readFileSync(),则会收到错误 Error: ENOENT, no such file or directory
。
如何捕获抛出的异常? doco 没有说明抛出了哪些异常,所以我不知道我需要捕获哪些异常。我应该注意,我不喜欢通用的“捕捉每一个可能的异常”风格的 try/catch 语句。在这种情况下,我希望捕获文件不存在时发生的特定异常,并尝试执行 readFileSync。
请注意,我仅在启动连接尝试之前执行同步功能,因此不需要我不应该使用同步功能的 cmets :-)
【问题讨论】:
你也可以使用fs.existsSync()
,如my new answer所示
【参考方案1】:
基本上,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'
希望这会有所帮助。
【讨论】:
谢谢,这就是我要找的信息。我只是假设这将是一种特定类型的错误。我也刚刚意识到我误解了 try/catch 的工作原理,我认为您可以捕获特定的错误类型(a la java)。感谢您提供信息戈洛。 :-) 另外EACCES
代码应该在if语句中检查文件存在但由于缺少权限而无法读取的情况【参考方案2】:
我更喜欢这种处理方式。您可以检查文件是否同步存在:
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');
注意:如果您的程序还删除了文件,则这会产生竞争条件,如 cmets 中所述。但是,如果您只写入或覆盖文件而不删除它们,那么这完全没问题。
【讨论】:
现在,fs.existsSync 是 not deprecated anymore:“请注意 fs.exists() 已弃用,但 fs.existsSync() 不是。” 一点也不好。如果文件在 existsSync 和 readFileSync 调用之间从磁盘中删除怎么办?您的代码现在有一个内置的竞争条件等待发生... @tkarls 是的,完全正确,这是 2015 年我还在学习 Node.js 时写的,它有一个竞争条件。然而,有两点需要注意:这种竞争条件的可能性很小,基本上可以忽略,第二个和取代第一个是我现在将使用 try/catch 和 async/await 使我的代码更灵活“其他”异常(因为 Node 对异常友好)。 比赛条件不重要,直到他们这样做。像这样的答案就是为什么软件漏洞百出,为什么需要经常重启计算机,为什么有这么多安全漏洞等等。Stack Overflow 应该有一个标记可能有害的答案。 我想在这里插话并同意所涉及的两个人的观点。但不同意@tkarls 黑白描述。例如,我正在编写用于解析磁盘上的 markdown 文件的代码,这些文件永远不会被删除。在这种情况下,当我知道永远不会出现这种竞争条件时,检查它是否存在比使用 try catch 作为控制流更有意义。软件工程不是对与错,是所有情况下的事情......【参考方案3】:您必须捕获错误,然后检查它是什么类型的错误。
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
【讨论】:
... 让那个 'throw err;' 有没有办法用函数的非同步版本捕获同样的错误? @KiJéy 异步代码将错误作为回调的第一个参数传递,因此如果您检查是否会得到相同的行为。【参考方案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。截至 2018 年 1 月 1 日,IE 不支持大约 77% 的浏览器使用率 (caniuse.com/#feat=arrow-functions) .我很好奇,你们是如何迎合IE用户的? @Metalskin Webpack + Babel。但是,fs
是一个 Node 模块
啊,我和node脱节了,我问这个问题时怀疑node不支持ES6(可能是错的)。有点忘了这也是一个节点问题;-)
更新这个...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/…
我相信如果promise被拒绝并且你正在等待promise,try-catch会被调用。【参考方案5】:
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
【讨论】:
【参考方案6】:尝试使用 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
编码愉快!
【讨论】:
Please note that I'm performing sync functions only on start up before serving connection attempts, so comments that I shouldn't be using sync functions are not required :-)
...
因此,请注意这种初始化逻辑的性能不佳,Observables/RxJS 是等待初始化而无需使用同步函数阻塞进程的不错选择以上是关于如何为 fs.readFileSync() 捕获没有文件?的主要内容,如果未能解决你的问题,请参考以下文章
fs.readFileSync 不是 Meteor 的函数,React
Node.JS fs.readFileSync() 错误参数
使用 lambda 部署时 fs.readFileSync 找不到文件