使用可写入stream写入文件时Node.js EBADF错误

我试图使用Node.js来处理一个500MB的Apache日志文件,从中转换它的语法

ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 

 ip.ip.ip.ip - - 02/Aug/2012:05:01:17 GET /path/of/access/ HTTP/1.1 302 26 

,然后写入另一个文本文件。

为了更好的内存控制和性能,我使用了fs.createReadStreamfs.createWriteStream ,但是只能把第一行写入output.txt ,因为脚本以错误结束:

{ [Error: EBADF, write] errno: 9, code: 'EBADF' }

在这里我发布了一些可能有助于debugging的信息。

input.txt头像:

 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 ip.ip.ip.ip - - [02/Aug/2012:05:01:18 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 

output.txt内容:

 ip.ip.ip.ip - - [02/Aug/2012:05:01:17 -0600] "GET /path/of/access/ HTTP/1.1" 302 26 

整个脚本:

 var fs = require('fs'); var data =''; var n=0; //For line control var r = fs.createReadStream('./input.txt',{ encoding: 'ascii', start:0, // end: 100000, }); var w = fs.createWriteStream('./output.txt',{ encoding:'ascii' }); function put(line){ //write into w; ++n; w.write(line+'\n'); } function end(){ r.destroy(); w.destroy(); } function onData(chunk){ var hasNewline = chunk.indexOf('\n')!==-1; if(hasNewline){ var arr = chunk.split('\n'); var first = arr.shift(); var last = arr.pop(); data+=first; put(data); //write a complete line arr.forEach(function(line){ put(line); //write a complete line }); data=last; }else{ data+=chunk; } if(n>100){ end(); } } function onErr(e){ console.log(e); } r.addListener( "data", onData); r.addListener( "end", end); r.addListener('error',onErr); w.addListener('error',onErr); 

你有两个我能看到的问题。

第一个是你的end函数在ReadStream上调用destroy ,但是在一般情况下,这是从end事件触发的,这意味着stream已经closures了,它将自动调用destroy 。 这意味着r.destroy将被调用两次,引发错误。 这是您看到打印错误的原因。

第二个问题是你在WriteStream上调用destroy 。 我build议你去阅读文档: http : //nodejs.org/api/stream.html#stream_stream_destroy_1

特别是Any queued write data will not be sent ,这就是为什么你错过了一些输出。

基本上,你应该只需要在ReadStream上调用destroy ,如果你想让它closures的话,就像在你的n > 100情况下一样。 然后,您想要使用WriteStream的end ,所以stream有时间写入所有缓冲的数据。

这是一个简化的版本,我认为应该是一样的。 我也不打扰绑定error因为错误自动打印到控制台。

 var fs = require('fs'); var data =''; var n=0; //For line control var r = fs.createReadStream('./input.txt',{ encoding: 'ascii', start:0, // end: 100000, }); var w = fs.createWriteStream('./output.txt',{ encoding:'ascii' }); r.addListener( "data", function(chunk){ data += chunk; var lines = data.split('\n'); data = lines.pop(); lines.forEach(function(line){ if (!r.readable) return; // If already destroyed if (n >= 100) { // Stop any more 'data' events and close the file. // This will also trigger 'close' below and close the writestream. r.destroy(); return; } n++; w.write(line + '\n'); }); }); r.addListener( "end", function(){ // When we hit the end of the file, close the write stream, // and write any remaining line content w.write(data); }); r.addListener("close", function(){ w.end(); });