流
Stream是Node.js中的抽象接口,有不少Node.js对象实现自Stream。
所有的Stream对象都是EventEmitter 的实例。
例如:fs模块(用于读写操作文件的模块)
fs的FSWatcher接口继承自events.EventEmitter,以下是fs模块的部分源码:
1 interface FSWatcher extends events.EventEmitter { 2 close(): void; 3 /** 4 * events.EventEmitter 5 * 1. change 6 * 2. error 7 */ 8 addListener(event: string, listener: (...args: any[]) => void): this; 9 addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; 10 addListener(event: "error", listener: (error: Error) => void): this; 11 on(event: string, listener: (...args: any[]) => void): this; 12 on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; 13 on(event: "error", listener: (error: Error) => void): this; 14 once(event: string, listener: (...args: any[]) => void): this; 15 once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; 16 once(event: "error", listener: (error: Error) => void): this; 17 18 prependListener(event: string, listener: (...args: any[]) => void): this; 19 prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; 20 prependListener(event: "error", listener: (error: Error) => void): this; 21 prependOnceListener(event: string, listener: (...args: any[]) => void): this; 22 prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; 23 prependOnceListener(event: "error", listener: (error: Error) => void): this; 24 }
在源码中我们可以看出,fs模块提供了不少的事件,如“error”、“change”等。 通过事件监听,我们可以方便的监控文件操作时的状态,例如可以监听error事件来判断文件读写是否出错。
对流的操作一般由以下几种:
1、读取流
1 var fs = require("fs"); 2 var readerStream = fs.createReadStream('test.txt');//读取test文件
2、写入流
1 var fs = require("fs"); 2 var writerStream = fs.createWriteStream('test.txt'); 3 writerStream.write('test_data','UTF8');//写入test文件
3、管道流,即输出流转入输入流(可用于文件下载)
1 var fs = require("fs"); 2 var readerStream = fs.createReadStream('input.txt'); 3 var writerStream = fs.createWriteStream('output.txt'); 4 readerStream.pipe(writerStream);
4、链式流, 链式是通过连接输出流到另外一个流并创建多个流操作链的机制
1 var fs = require("fs"); 2 var zlib = require('zlib');//压缩及解压缩模块 3 //压缩input.txt到input.txt.gz 4 fs.createReadStream('input.txt') 5 .pipe(zlib.createGzip()) 6 .pipe(fs.createWriteStream('input.txt.gz'));
利用流的特性我们写一个文件下载的范例:
1 const fs = require("fs"); 2 module.exports = { 3 downloadApp(req, res, next) { 4 var name = "XXX.apk"; 5 var path = 'download_file/' + name; 6 fs.exists(path, function (exists) { 7 if (exists) { 8 var size = fs.statSync(path).size; 9 var f = fs.createReadStream(path); 10 f.on('error', function (err) {//监听error事件判断文件读写是否出错 11 console.log(err.stack); 12 //此处可以记log 13 }); 14 res.writeHead(200, { 15 'Content-Type': 'application/force-download', 16 'Content-Disposition': 'attachment; filename=' + name, 17 'Content-Length': size 18 }); 19 f.pipe(res);//将读取的文件流写入输出流 20 } 21 }); 22 }, 23 }
Node.js的文件操作
Node.js中有对文件操作功能非常丰富的模块,就是在上文中我们提到的fs模块。fs模块的所有文件操作函数都提供同步和异步,不过通常使用异步较多(非阻塞特性)。
1 var fs = require("fs"); 2 // 异步读取 3 fs.readFile('test.txt', function (err, data) { 4 if (err) { 5 return console.error(err); 6 } 7 console.log("异步读取: " + data.toString()); 8 }); 9 // 同步读取 10 var data = fs.readFileSync('test.txt'); 11 console.log("同步读取: " + data.toString());
除此之外,fs提供了众多操作,以下是其中一部分:
fs.open(path[, flags[, mode]], callback)
- path <string> | <Buffer> | <URL>
- flags <string> | <number> 参阅支持的文件系统标志。默认值: 'r'。
- mode <integer> 默认值: 0o666(可读写)。
- callback <Function>
- err <Error>
- fd <integer>
fs.write(fd, buffer[, offset[, length[, position]]], callback)
- fd <integer>
- buffer <Buffer> | <TypedArray> | <DataView>
- offset <integer>
- length <integer>
- position <integer>
- callback <Function>
- err <Error>
- bytesWritten <integer>
- buffer <Buffer> | <TypedArray> | <DataView>
fs.writeFile(file, data[, options], callback)
- file <string> | <Buffer> | <URL> | <integer> 文件名或文件描述符。
- data <string> | <Buffer> | <TypedArray> | <DataView>
- options <Object> | <string>
- encoding <string> | <null> 默认值: 'utf8'。
- mode <integer> 默认值: 0o666。
- flag <string> 参阅支持的文件系统标志。默认值: 'w'。
- callback <Function>
- err <Error>
当 flag 选项采用字符串时,可用以下标志:
- 'a' - 打开文件用于追加。如果文件不存在,则创建该文件。
- 'ax' - 与 'a' 相似,但如果路径已存在则失败。
- 'a+' - 打开文件用于读取和追加。如果文件不存在,则创建该文件。
- 'ax+' - 与 'a+' 相似,但如果路径已存在则失败。
- 'as' - 以同步模式打开文件用于追加。如果文件不存在,则创建该文件。
- 'as+' - 以同步模式打开文件用于读取和追加。如果文件不存在,则创建该文件。
- 'r' - 打开文件用于读取。如果文件不存在,则出现异常。
- 'r+' - 打开文件用于读取和写入。如果文件不存在,则出现异常。
- 'w' - 打开文件用于写入。如果文件不存在则创建文件,如果文件已存在则截断文件。
- 'wx' - 与 'w' 相似,但如果路径已存在则失败。
- 'w+' - 打开文件用于读取和写入。如果文件不存在则创建文件,如果文件已存在则截断文件。
- 'wx+' - 与 'w+' 相似,但如果路径已存在则失败。