流
Stream是Node.js中的抽象接口,有不少Node.js對象實現自Stream。
所有的Stream對象都是EventEmitter 的實例。
例如:fs模塊(用於讀寫操作文件的模塊)
fs的FSWatcher接口繼承自events.EventEmitter,以下是fs模塊的部分源碼:
interface FSWatcher extends events.EventEmitter {
close(): void;
/**
* events.EventEmitter
* 1. change
* 2. error
*/
addListener(event: string, listener: (...args: any[]) => void): this;
addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
addListener(event: "error", listener: (error: Error) => void): this;
on(event: string, listener: (...args: any[]) => void): this;
on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
on(event: "error", listener: (error: Error) => void): this;
once(event: string, listener: (...args: any[]) => void): this;
once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
once(event: "error", listener: (error: Error) => void): this;
prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
prependListener(event: "error", listener: (error: Error) => void): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
prependOnceListener(event: "error", listener: (error: Error) => void): this;
}
在源碼中我們可以看出,fs模塊提供了不少的事件,如“error”、“change”等。 通過事件監聽,我們可以方便的監控文件操作時的狀態,例如可以監聽error事件來判斷文件讀寫是否出錯。
對流的操作一般由以下幾種:
1、讀取流
var fs = require("fs");
var readerStream = fs.createReadStream('test.txt');//讀取test文件
2、寫入流
var fs = require("fs");
var writerStream = fs.createWriteStream('test.txt');
writerStream.write('test_data','UTF8');//寫入test文件
3、管道流,即輸出流轉入輸入流(可用於文件下載)
var fs = require("fs");
var readerStream = fs.createReadStream('input.txt');
var writerStream = fs.createWriteStream('output.txt');
readerStream.pipe(writerStream);
4、鏈式流, 鏈式是通過連接輸出流到另外一個流並創建多個流操作鏈的機制
var fs = require("fs");
var zlib = require('zlib');//壓縮及解壓縮模塊
//壓縮input.txt到input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
利用流的特性我們寫一個文件下載的範例:
const fs = require("fs");
module.exports = {
downloadApp(req, res, next) {
var name = "XXX.apk";
var path = 'download_file/' + name;
fs.exists(path, function (exists) {
if (exists) {
var size = fs.statSync(path).size;
var f = fs.createReadStream(path);
f.on('error', function (err) {//監聽error事件判斷文件讀寫是否出錯
console.log(err.stack);
//此處可以記log
});
res.writeHead(200, {
'Content-Type': 'application/force-download',
'Content-Disposition': 'attachment; filename=' + name,
'Content-Length': size
});
f.pipe(res);//將讀取的文件流寫入輸出流
}
});
},
}
Node.js的文件操作
Node.js中有對文件操作功能非常豐富的模塊,就是在上文中我們提到的fs模塊。fs模塊的所有文件操作函數都提供同步和異步,不過通常使用異步較多(非阻塞特性)。
var fs = require("fs");
// 異步讀取
fs.readFile('test.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("異步讀取: " + data.toString());
});
// 同步讀取
var data = fs.readFileSync('test.txt');
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+' 相似,但如果路徑已存在則失敗。