今天在学习node.js流的时候,参照菜鸟教程的文档写了从流中读取和写入数据的操作,但是在两者同时运行的时候,却发现写入文档并没有任何数据写入。
先上最初的错误代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| var fs = require('fs'); var data = '';
var readerStream = fs.createReadStream('input.txt'); var writerStream = fs.createWriteStream('output.txt');
readerStream.on('data', function(chunk){ console.log("1、Start:"); data += chunk; }); readerStream.on('end', function(){ console.log("2、" + data); }); readerStream.on('error', function(err){ console.log(err.stack); });
writerStream.write(data, 'UTF8'); writerStream.end(); writerStream.on('finish', function(){ console.log("3、Write done!"); console.log("4、All done!"); }); writerStream.on('err', function(err){ console.log(err.stack); });
console.log("5、Program Finished!");
|
程序的运行结果如下:
1 2 3 4 5
| 5、Program Finished! 1、Start: 3、Write done! 4、All done! 2、Hello world!
|
这时去查看同目录下生成的output.txt是没有内容的,根据以上代码,显然在进行写入操作时,data变量还没有数据读入,因此output写入数据为空(你也可以尝试定义data为一个字符串进行测试)。
接下来对写入流(writerStream)设定一个定时器,1秒后进行操作,修改代码为:
1 2 3 4 5 6 7 8
| ... setTimeout(function(){ writerStream.write(data, 'UTF8'); },1000); setTimeout(function(){ writeStream.end(); },2000) ...
|
这里需要注意,在对写操作设置定时器的时候,需要对end方法也设定定时器,并且时间需要大于我们写操作定时器的时间,不然会出现以下错误:
1 2
| Error: write after end ...
|
最终调试到以下阶段:
1 2 3 4 5 6 7 8 9
| ... setTimeout(function(){ writerStream.write(data, 'UTF8'); },3);
setTimeout(function(){ writeStream.end(); },5) ...
|
可以看到从文件中读取数据至少要3ms(实际的读取时间跟文件路径以及大小有关),而程序读取完只需要不到1ms,所以才出现了最开始写入数据为空的bug。这也侧面说明了node.js的异步处理方式。
当然,其实node.js已经帮我们做好了这一堆繁杂的操作,管道流(pipe)很好的解决了这一个问题,我们的代码可以简化为:
1 2 3 4 5 6 7
| var fs = require('fs');
var readerStream = fs.createReadStream('input.txt'); var writeeStream = fs.createWriteStream('output.txt');
readerStream.pipe(writeStream); console.log("All done!");
|
上述的操作会使得output.txt内容被覆写,如果你只想在output.txt中追加内容,可以在定义写入流的时候追加参数:
1
| var writeeStream = fs.createWriteStream('output.txt',{'flags' : 'a' });
|
可用的参数列表如下:
| flag |
说明 |
| r |
读取文件。如果文件不存在则抛出异常 |
| r+ |
读取并写入。如果文件不存在时抛出异常 |
| rs |
以同步方式读取文件并通知操作系统忽略本地文件系统缓存 |
| w |
写入文件。文件不存在则创建该文件,存在则清空文件内容 |
| w+ |
读取并写入文件。文件不存在则创建该文件,存在则清空文件内容 |
| wx |
作用与”w”类似。但以排他方式打开文件 |
| wx+ |
作用与”w+”类似。但以排他方式打开文件 |
| a |
以追加方式写入文件。如果文件不存在则创建该文件 |
| a+ |
读取并以追加方式写入文件。如果文件不存在则创建该文件 |
| ax |
作用与”a”相似。但以排他方式打开文件 |
| ax+ |
作用与”a+”相似。但以排他方式打开文件 |