使用 require vs fs.readFile 读取 json 文件内容
Posted
技术标签:
【中文标题】使用 require vs fs.readFile 读取 json 文件内容【英文标题】:Read json file content with require vs fs.readFile 【发布时间】:2016-05-25 03:56:54 【问题描述】:假设对于来自 API 的每个响应,我需要将响应中的值映射到我的 Web 应用程序中的现有 json 文件并显示来自 json 的值。在这种情况下,读取 json 文件的更好方法是什么?要求或 fs.readfile。请注意,可能同时有数千个请求进来。
请注意,我不希望在运行时对文件有任何更改。
request(options, function(error, response, body)
// compare response identifier value with json file in node
// if identifier value exist in the json file
// return the corresponding value in json file instead
);
【问题讨论】:
【参考方案1】:
"country": [
"INDIA",
"USA"
],
"codes": [
"IN",
"US"
]
// countryInfo.json
const country, code = require('./countryInfo.json');
console.log(country[0]); // "INDIA"
console.log(code[0]); // "IN"
【讨论】:
通过对象解构你可以做到const country, code = require('countryInfo.json');
【参考方案2】:
由于从来没有人愿意编写基准测试,而且我感觉需要更快地工作,所以我自己做了一个。
我比较了 fs.readFile(承诺版本)与 require(无缓存)与 fs.readFileSync。
您可以查看基准here 和结果here。
对于 1000 次迭代,它看起来像这样:
require: 835.308ms
readFileSync: 666.151ms
readFileAsync: 1178.361ms
那么你应该使用什么?答案没那么简单。
-
当您需要永久缓存对象时使用 require。并更好地使用 Object.freeze 以避免在应用程序中对其进行变异。
在单元测试或阻止应用程序启动时使用 readFileSync - 这是最快的。
当应用程序正在运行并且您不想阻塞事件循环时,请使用 readFile 或 promisified 版本。
【讨论】:
【参考方案3】:如果你的文件是空的,require 将会中断。会报错:
SyntaxError ... JSON 输入意外结束。
使用readFileSync/readFile
你可以处理这个问题:
let routesJson = JSON.parse(fs.readFileSync('./routes.json', 'UTF8') || '');
或:
let routesJson
fs.readFile('./dueNfe_routes.json', 'UTF8', (err, data) =>
routesJson = JSON.parse(data || '');
);
【讨论】:
【参考方案4】:我只想指出,即使应该删除变量,require
似乎也会将文件保留在内存中。我有以下案例:
for (const file of fs.readdirSync('dir/contains/jsons'))
// this variable should be deleted after each loop
// but actually not, perhaps because of "require"
// it leads to "heap out of memory" error
const json = require('dir/contains/jsons/' + file);
for (const file of fs.readdirSync('dir/contains/jsons'))
// this one with "readFileSync" works well
const json = JSON.parse(fs.readFileSync('dir/contains/jsons/' + file));
require
的第一个循环由于“堆内存不足”错误而无法读取所有 JSON 文件。 readFile
的第二个循环有效。
【讨论】:
【参考方案5】:如果在测试中处理 JSON 固定装置,请使用 node-fixtures。
该项目将寻找一个名为 fixtures 的目录,该目录必须是您的测试目录的子目录,以便加载所有的fixtures(*.js 或 *.json 文件):
// test/fixtures/users.json
"dearwish":
"name": "David",
"gender": "male"
,
"innaro":
"name": "Inna",
"gender": "female"
// test/users.test.js
var fx = require('node-fixtures');
fx.users.dearwish.name; // => "David"
【讨论】:
【参考方案6】:fs.readFile
有两个版本,分别是
异步版本
require('fs').readFile('path/test.json', 'utf8', function (err, data)
if (err)
// error handling
var obj = JSON.parse(data);
);
同步版本
var json = JSON.parse(require('fs').readFileSync('path/test.json', 'utf8'));
使用require
解析json文件如下
var json = require('path/test.json');
但是,请注意
require
是同步的,只读取一次文件,随后的调用从 cache
如果您的文件没有.json
扩展名,require 不会将文件内容视为JSON
。
【讨论】:
我想知道为什么我的 require('file.json') 一直在变化,直到我读到这个 - “require 是同步的,只读取一次文件,之后调用从缓存中返回结果”。这可以通过 - delete require.cache[require.resolve('file.json')] 绕过【参考方案7】:我想你会 JSON.parse json 文件进行比较,在这种情况下,require
更好,因为它会立即解析文件并同步:
var obj = require('./myjson'); // no need to add the .json extension
如果您有数千个使用该文件的请求,请在您的请求处理程序之外要求它一次,就是这样:
var myObj = require('./myjson');
request(options, function(error, response, body)
// myObj is accessible here and is a nice javascript object
var value = myObj.someValue;
// compare response identifier value with json file in node
// if identifier value exist in the json file
// return the corresponding value in json file instead
);
【讨论】:
require
不是同步的吗?根据 JSON 文件或用例的大小,fs.readFile 应该更好。
我也同意甚至建议使用管道处理更大的文件。对于大型连接,连接的归类(空间/时间索引)也被证明可以提高效率。
值得注意的是,require
会缓存文件,因此如果该 json 文件的内容在应用程序的整个生命周期内发生变化,您将看不到更新
值得注意的是,由于require
缓存,当您对对象进行变异时,您也会对所有未来的调用进行变异(因此本质上它充当单例)。我遇到的问题是我在多个测试用例中使用了相同的require("test-payload.json")
,并在途中更改了一些属性。结果,一个测试用例在单独运行时通过,但在与所有其他测试一起运行时失败。所以请注意这一点,并在需要时使用扩展运算符来制作对象副本。以上是关于使用 require vs fs.readFile 读取 json 文件内容的主要内容,如果未能解决你的问题,请参考以下文章
异步/等待函数,fs.readfile 并将其存储到变量 [重复]
如何将使用 fs.readFileSync() 的 Node.js 代码重构为使用 fs.readFile()?