使用 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()?

Webpack nodejs fs.readFile 不是函数

node 基础API(fs)

nodeJS文件流和事件

Node.JS文件系统解析