2011-10-25 116 views
2

我试图写一点JS读取文件并将其写入流。这笔交易是文件非常大,所以我必须一点一点地阅读它。似乎我不应该用尽内存,但我确实是这样。下面的代码:Node.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,然后将其从内存中丢弃,但我可能是错的。有些东西导致数据留在内存中,我不知道它会是什么。任何帮助将不胜感激。

+1

'删除BUF;'无效,尝试'BUF = null' – Raynos

回答

1

the documentationdata_output.write(...)将返回true如果字符串已被刷新,并false若没有(由于内核缓冲区已满)。这是什么样的流?

另外,我(相当)确定这不是问题,但是:你如何在每次循环迭代时分配一个新的Buffer?在循环之前初始化buf是否更有意义?

+0

啊,良好的通话。这就是我只是在调试,试图找出是否在每次迭代后删除它会做任何事情。这实际上是将大文件发送到远程存储,并且它是HTTP。 –

+0

回复:HTTP:这是有道理的。您可以比通过网络发送文件更快地读取文件,并且只有在实际发送字节之前,“写入”才会被阻止。 (如果它们还没有发送,它会返回'false',然后在它们发出后再发出'drain'事件。) – ruakh

2

您应该使用的管道,如:

var fp = fs.createReadStream("tmpfile.tmp"); 
fp.pipe(data_output); 

欲了解更多信息,请上网:http://nodejs.org/docs/v0.5.10/api/streams.html#stream.pipe

编辑:在您的实现问题,顺便说一句,就是通过做它像块写缓冲区不会被刷新,并且在将大部分文件写回去之前,您将读取整个文件。

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(); 
3

我有一个非常类似的问题。我正在阅读一个带有10M行的非常大的csv文件,并写出了它的json等价物。我在Windows任务管理器中看到我的进程使用了​​> 2GB的内存。最终我发现输出流可能比输入流慢,并且输出流缓冲了大量的数据。我能够通过暂停每100次写入外流并等待外流清空来解决这个问题。这给了外面的时间赶上了流动。我认为这不是为了讨论的缘故,但我使用'readline'一次处理一行csv文件。

我也想通过这种方式,如果不是将每一行写到外面,而是将100条左右的行连接在一起,然后将它们写在一起,这也改善了内存情况并提高了操作速度。

最后,我发现我可以使用70M的内存来完成文件传输(csv - > 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 = ""; 
    } 
}