Node.js / V8:如何将大文件读入内存?

6

问题

如何在node.js下将大于1.1GB的文件读入内存?

示例

我正在尝试在node.js下使用topojson将大于1.1GB的GeoJSON文件转换为TopoJSON格式。

$ topojson -o outfile.json larger_than_one_point_one_GB_input_file.json

(以上方法适用于不超过517 MB的文件)

导致以下错误

buffer.js:242
this.parent = new SlowBuffer(this.length);
                    ^
RangeError: length > kMaxLength
    at new Buffer (buffer.js:242:21)
    at Object.fs.readFileSync (fs.js:200:14)
    at /usr/local/share/npm/lib/node_modules/topojson/bin/topojson:61:26
    at Array.forEach (native)
    at Object.<anonymous> (/usr/local/share/npm/lib/node_modules/topojson/bin/topojson:60:8)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:492:10)

我尝试过的

  • 广泛搜索
  • 命令行内存设置
    • --max-stack-size=2147000000
    • --max_executable_size=2000
    • --max_new_space_size=2097152
    • --max_old_space_size=2097152
  • 编译最新的v8版本到自定义node.js安装中
    • 他们似乎已经移除了这个内存限制(如果我正确的话,我可能不正确)
    • 这没有成功

版本

  • node.js:v0.8.15
  • v8:3.11.10.25
1个回答

2
问题是因为 topojson 使用 fs.readFileSync 来读取整个文件。这样做会打开一个大小为(文件长度)的缓冲区,然后填充它。但是 Node 缓冲区 有一个最大大小0x3FFFFFFF 字节,即 1GB - 1 byte。所以你会得到那个异常。
解决方案是什么?打开 topojson 源代码,用流方法替换 readFileSync,这样就不会将整个文件作为一个块读取。或者如果你感觉真的很 hackish,也可以重新编译 Node 并使用更大的 kMaxLength 常量...

有趣。我会尝试使用流式方法替换readFileSync。如果成功了,我很乐意将您的答案标记为正确答案。谢谢! - Jeff
祝你好运 - 我不知道这会有多容易,因为你可能还需要改变其他一些东西,比如稍后的 JSON.stringify 调用 - 这也可能会出现相同的错误。 - configurator
很不幸,到目前为止我还没有成功。可能是因为我的javascript和node.js技能不够强。我将文件作为流读取,但无法将其写入内存(同样的问题)。重新写回磁盘没有意义。也许有一些智能的方法可以将其分割成多个缓冲区…… - Jeff
你可以尝试重新编译Node以进行此特定的一次操作。就像我说的那样,这很粗糙,但对于一次性运行应该可以工作。您唯一需要做出的更改是kMaxLength常量。从我的粗略扫描中,看起来其他所有内容都应该“只是工作”。 - configurator
哦,deps/v8/src/objects.h 中的一些常量可能也需要更改。 - configurator
非常感谢您在这里提供的所有建议和意见。我必须承认,经过几次努力后,我的技能已经达到了极限。如果我有所突破,我会更新这篇文章!再次感谢。 - Jeff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接