为什么我的fs.readFile返回的是一个缓冲区而不是XML?

10 浏览
0 Comments

为什么我的fs.readFile返回的是一个缓冲区而不是XML?

我有一个名为fetchXML的函数,它应该将一个名为feed.xml的XML文件写入我的根目录,并且我想要在控制台中输出feed.xml中的数据。我使用了fs.readFile,并且在这个问题中指定了编码为'utf-8':为什么Node.js的fs.readFile()返回一个缓冲区而不是字符串?

但是我的console.log的结果仍然是一个缓冲区。我检查了feed.xml内部,它确实包含了XML数据。

var out = fs.createWriteStream('./feed.xml');
var fetchXML = function() {
  var feedURL = 'http://www2.jobs2careers.com/feed.php?id=1237-2595&c=1&pass=HeahE0W1ecAkkF0l';
  var stream = request(feedURL).pipe(zlib.createGunzip()).pipe(out);
  stream.on('finish', function() {
    fs.readFile('./feed.xml', 'utf-8', function(err, data) {
      console.log(data);
    });
  });
}
fetchXML();

0
0 Comments

问题的原因是,当使用fs.readFile读取文件时,如果文件过大,将无法将其转换为JavaScript字符串,而会返回一个Buffer对象。这是因为V8引擎的字符串大小限制,当前最大字符串大小约为268mb,而某些XML文件可能会超过这个限制。

解决方法是使用逐块解析的流解析器,而不是尝试将整个XML文件作为一个巨大的字符串首先加载,然后再解析。对于XML文件的流解析,可以使用node-expat模块。

在使用node-expat时,需要使用各种回调函数来处理XML的不同部分,如startElement、endElement等。具体如何使用这些函数可以参考相关文档或示例代码。

通过使用流解析器,可以逐块解析XML文件,避免了字符串大小限制的问题,同时也提高了解析大型文件的效率。

文章整理如下:

问题:为什么我的fs.readFile返回的是一个Buffer而不是XML?

主要问题在于,在这种情况下设置了err,并且它会告诉您toString()失败(由于文件的大小)。然后,它将读取的数据作为Buffer留在那里,并将其作为第二个参数传递给回调函数。

这可能被视为部分bug,因为大多数人可能不会预期会传递第二个参数,但与此同时err被设置了(您应该始终处理错误),并且它确实提供了一个机会来对已经读入内存的(原始二进制)数据进行其他操作。

至于解决方案,对于这样大量的数据(数百兆字节),您可能会希望使用流解析器。对于XML文件,一个提供流接口的模块是node-expat。

我想使用xml2js将XML转换为JSON,但当我尝试使用"data"时,返回的是undefined而不是JSON。我认为这可能与它返回一个buffer有关。

对于非常大的文档,您将希望使用流解析器,正如我现在在我的答案中指出的那样。

我到底想用流解析器实现什么?老实说,我对我的当前解决方案为什么不起作用有点困惑。我以前从未做过这样的事情,所以您需要给我一个基本的解释。

V8引擎有一个最大字符串大小限制,当您要求Node将原始二进制数据转换为JavaScript字符串时,它会失败,因为数据太大。在这种情况下,XML数据超过300mb,而V8当前的最大字符串大小约为268mb。如果使用流解析器,可以将XML逐块解析,而不是首先尝试将整个XML文件作为一个巨大的字符串加载,然后再解析。

好的,这有道理。对于node-expat,我需要使用哪个函数?我看到有各种函数,如startElement、endElement等,但它们的用法并不是很明显...

0