文件流
流是指数据的流动,数据从一个地方缓慢的流动到一个地方。流是有方向的
流的分类:
- 可读流:Readable 数据从源头流向内存;
- 可写流:Writable 数据从内存流向源头;
- 双工流:Duplex 数据既可以从源头流向内存,又可以从内存流向源头;
文件可读流
fs.craeteReadStream(path,[options])
创建一个文件可读流,用于读取文件内容
参数
path:读取文件路径
options:配置
- ecoding:编码方式,默认为null,读出内容为buffer
- start:起始字节
- end:结束字节
- highWaterMark:每次读取字节数,默认为 64*1024字节
- autoClose:读完后自动关闭,默认值为true
返回值
Readable的子类ReadStream
事件
通过返回值得到的ReadStream的绑定,.on(事件种类,函数)
open
文件打开事件,文件被打开时触发
const rs = fs.createReadStream(filename, {
encoding: 'utf-8',
highWaterMark: 1
})
// 文件打开事件
rs.on('open', () => {
console.log('文件被打开了!')
})
close
文件关闭后触发
文件关闭的两种方法:
- 可读流.close(); 手动关闭
- 文件读完后自动关闭
test.txt: I am a Chinese!
// 创建文件可读流
const rs = fs.createReadStream(filename, {
encoding: 'utf-8',
highWaterMark: 1
})
// 文件关闭事件
rs.on('close', () => {
console.log('文件关闭!')
})
rs.close();
输出:文件关闭!
error
读取文件出现错误
data
读取到一部分数据后触发,注册data后才会开始读取文件,每次读取highWaterMark指定的数量,回调函数中会附带读到的数据。
const fs = require('fs');
const path = require('path');
const filename = path.resolve(__dirname, './test.txt')
// 创建文件可读流
const rs = fs.createReadStream(filename, {
encoding: 'utf-8',
highWaterMark: 1
})
// 文件读取事件
rs.on('data', chunk => {
console.log('文件内容:', chunk)
})
输出:
文件内容: I
文件内容:
文件内容: a
文件内容: m
文件内容:
文件内容: a
文件内容:
文件内容: C
文件内容: h
文件内容: i
文件内容: n
文件内容: e
文件内容: s
文件内容: e
文件内容: !
end
全部数据读取完毕!
rs.pause()
暂停读取,会触发pause事件
rs.resume()
恢复读取,会触发resume事件
文件可写流
fs.craeteWriteStream(path,[options])
参数
path: 路径
options:配置
- flags: 操作文件的方式,w:覆盖文件;a:追加文件;
- ecoding: 编码方式,默认UTF-8
- start:起始字节
- highWaterMark:每次最多写入的字节数
返回值
Writable的子类WriteStream
事件
.on(事件种类,函数)
open
打开文件
error
读取文件出错
close
关闭文件
ws.write(data)
写入一组数据,data:字符串或buffer
返回值为boolean值:
- true:写入通道没有被填满,接下来的数据可以直接写入,无需排队;
- false:写入通道已被填满,接下来的数据将进入写入队列;
当写入队列排满后再清空时,会触发drain事件。
ws.end([data])
需要手动调用;
结束写入,将自动关闭文件;
data是可选的,表示关闭前的最后一次写入内容;
rs.pipe(ws)
将可读流连接到可写流,可解决背压问题;返回值为ws
文件复制
使用pipe
const fs = require('fs');
const path = require('path');
const from = path.resolve(__dirname, './test.png');
const to = path.resolve(__dirname, './testCopy.png');
const rs = fs.createReadStream(from);
const ws = fs.createWriteStream(to);
rs.pipe(ws);
手写,使用可读流和可写流
const fs = require('fs');
const path = require('path');
const from = path.resolve(__dirname, './test.png');
const to = path.resolve(__dirname, './testCopy.png');
const rs = fs.createReadStream(from);
const ws = fs.createWriteStream(to);
rs.on('data', chunk => {
const flag = ws.write(chunk);
if (!flag) {
// 写入队列即将排满
rs.pause(); //暂停
}
})
ws.on('drain', () => {
rs.resume(); //继续读
})
rs.on('end', () => {
ws.end(); //结束写入
console.log('复制完成!');
})
使用readFile和writeFile
const from = path.resolve(__dirname, './test.png');
const to = path.resolve(__dirname, './testCopy.png');
const fileContent = fs.promises.readFile(from).then(data => {
fs.promises.writeFile(to, data).then(() => {
console.log('复制完成!');
});
})