const fs = require('fs'); //创建一个文件可写流 let ws = fs.createWriteStream('./1.txt', { highWaterMark: 3 }); //往流中写入数据 //参数一表示要写入的数据 //参数二表示编码方式 //参数三表示写入成功的回调 //缓冲区满时返回false,未满时返回true。 //由于上面我们设置的缓冲区大小为 3字节,所以到写入第3个时,就返回了false。 console.log(ws.write('1', 'utf8')); console.log(ws.write('2', 'utf8')); console.log(ws.write('3', 'utf8')); console.log(ws.write('4', 'utf8')); //调用end()表明已经没有数据要被写入,在关闭流之前再写一块数据。 //如果传入了回调函数,则将作为 'finish' 事件的回调函数 ws.end('最后一点数据', 'utf8'); //调用 end() 且缓冲区数据都已传给底层系统时触发 ws.on('finish', function () { console.log('写入完成'); });
写入流的 cork() 和 uncork() 方法,主要是为了解决大量小块数据写入时,内部缓冲可能失效,导致的性能下降。
const fs = require('fs'); let ws = fs.createWriteStream('./1.txt', { highWaterMark: 1 }); //调用 cork() 后,会强制把所有写入的数据缓冲到内存中。 //不会因为写入的数据超过了 highWaterMark 的设置而写入到文件中。 ws.cork(); ws.write('1'); console.log(ws.writableLength); ws.write('2'); console.log(ws.writableLength); ws.write('3'); console.log(ws.writableLength); //将调用 cork() 后的缓冲数据都输出到目标,也就是写入文件中。 ws.uncork();
注意 cork() 的调用次数要与 uncork() 一致。
const fs = require('fs'); let ws = fs.createWriteStream('./1.txt', { highWaterMark: 1 }); //调用一次 cork() 就应该写一次 uncork(),两者要一一对应。 ws.cork(); ws.write('4'); ws.write('5'); ws.cork(); ws.write('6'); process.nextTick(function () { //注意这里只调用了一次 uncork() ws.uncork(); //只有调用同样次数的 uncork() 数据才会被输出。 ws.uncork(); });
六、可读流的 pipe() 方法
pipe() 方法类似下面的代码,在可读流与可写流之前架起一座桥梁。
const fs = require('fs'); //创建一个可读流 let rs = fs.createReadStream('./1.txt', { highWaterMark: 3 }); //创建一个可写流 let ws = fs.createWriteStream('./2.txt', { highWaterMark: 3 }); rs.on('data', function (data) { let flag = ws.write(data); console.log(`往可写流中写入 ${data.length} 字节数据`); //如果写入缓冲区已满,则暂停可读流的读取 if (!flag) { rs.pause(); console.log('暂停可读流'); } }); //监控可读流数据是否读完 rs.on('end', function () { console.log('数据已读完'); //如果可读流读完了,则调用 end() 表示可写流已写入完成 ws.end(); }); //如果可写流缓冲区已清空,可以再次写入,则重新打开可读流 ws.on('drain', function () { rs.resume(); console.log('重新开启可读流'); });
我们用 pipe() 方法完成上面的功能。
const fs = require('fs'); //创建一个可读流 let rs = fs.createReadStream('./1.txt', { highWaterMark: 3 }); //创建一个可写流 let ws = fs.createWriteStream('./2.txt', { highWaterMark: 3 }); let ws2 = fs.createWriteStream('./3.txt', { highWaterMark: 3 }); //绑定可写流到可读流,自动将可读流切换到流动模式,将可读流的所有数据推送到可写流。 rs.pipe(ws); //可以绑定多个可写流 rs.pipe(ws2);
我们也可以用 unpipe() 手动的解绑可写流。
const fs = require('fs'); //创建一个可读流 let rs = fs.createReadStream('./1.txt', { highWaterMark: 3 }); //创建一个可写流 let ws = fs.createWriteStream('./2.txt', { highWaterMark: 3 }); let ws2 = fs.createWriteStream('./3.txt', { highWaterMark: 3 }); rs.pipe(ws); rs.pipe(ws2); //解绑可写流,如果参数没写,则解绑所有管道 setTimeout(function () { rs.unpipe(ws2); }, 0);