我正在尝试编写一些JS来读取文件并将其写入流中。这笔交易是文件非常大,所以我必须一点一点地读它。似乎我不应该耗尽内存,但我确实如此。这是代码:
var size = fs.statSync("tmpfile.tmp").size;
var fp = fs.openSync("tmpfile.tmp", "r");
for(var pos = 0; pos < size; pos += 50000){
var buf = new Buffer(50000),
len = fs.readSync(fp, buf, 0, 50000, (function(){
console.log(pos);
return pos;
})());
data_output.write(buf.toString("utf8", 0, len));
delete buf;
}
data_output.end();
出于某种原因,它命中264900000,然后抛出FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory
。我认为data_output.write()
调用会强制它将数据写入data_output
,然后将其从内存中丢弃,但我可能是错的。有些东西导致数据留在内存中,我不知道它会是什么。任何帮助将不胜感激。
答案 0 :(得分:3)
我有一个非常类似的问题。我在一个非常大的csv文件中读取10M行,并写出它的json等价物。我在Windows任务管理器中看到我的进程正在使用&gt; 2GB内存。最终我发现输出流可能比输入流慢,并且输出流缓冲了大量数据。我能够通过暂停每100次写入到流出的插入,并等待流出清空来解决这个问题。这为外流提供了赶上内流的时间。我不认为这对于这个讨论很重要,但是我使用'readline'来一次处理一行csv文件。
我还想到了如果不是将每一行写入流出,而是将100行连接在一起,然后将它们一起写入,这也改善了内存情况,并使操作更快。
最后,我发现只使用70M的内存就可以进行文件传输(csv - &gt; json)。
这是我的写函数的代码片段:
var write_counter = 0;
var out_string = "";
function myWrite(inStream, outStream, string, finalWrite) {
out_string += string;
write_counter++;
if ((write_counter === 100) || (finalWrite)) {
// pause the instream until the outstream clears
inStream.pause();
outStream.write(out_string, function () {
inStream.resume();
});
write_counter = 0;
out_string = "";
}
}
答案 1 :(得分:2)
您应该使用管道,例如:
var fp = fs.createReadStream("tmpfile.tmp");
fp.pipe(data_output);
有关详细信息,请查看:http://nodejs.org/docs/v0.5.10/api/streams.html#stream.pipe
编辑:你的实现中的问题,顺便说一下,通过像这样的块来做,写缓冲区不会被刷新,你将在写入大部分内容之前读取整个文件退出。答案 2 :(得分:1)
根据the documentation,如果字符串已被刷新,则data_output.write(...)
将返回true
,如果没有,则false
将返回(由于内核缓冲区已满)。这是什么样的流?
另外,我(相当)确定这不是问题,但是:为什么要在每次循环迭代中分配一个新的Buffer
?在循环之前初始化buf
会不会更有意义吗?
答案 3 :(得分:0)
我不知道同步文件函数是如何实现的,但您是否考虑过使用异步函数?这将更有可能允许垃圾收集和i / o刷新发生。因此,不是for循环,而是触发上一次读取的回调函数中的下一次读取。
这些方面的内容(另请注意,根据其他评论,我正在重复使用缓冲区):
var buf = new Buffer(50000),
var pos = 0, bytesRead;
function readNextChunk () {
fs.read(fp, buf, 0, 50000, pos,
function(err, bytesRead){
if (err) {
// handle error
}
else {
data_output.write(buf.toString("utf8", 0, bytesRead));
pos += bytesRead;
if (pos<size)
readNextChunk();
}
});
}
readNextChunk();