node的文件流

文件流

流是指数据的流动,数据从一个地方缓慢的流动到一个地方。流是有方向的

流的分类:

  • 可读流:Readable 数据从源头流向内存;
  • 可写流:Writable 数据从内存流向源头;
  • 双工流:Duplex 数据既可以从源头流向内存,又可以从内存流向源头;

文件可读流

fs.craeteReadStream(path,[options])

创建一个文件可读流,用于读取文件内容

参数

path:读取文件路径
options:配置

  • ecoding:编码方式,默认为null,读出内容为buffer
  • start:起始字节
  • end:结束字节
  • highWaterMark:每次读取字节数,默认为 64*1024字节
  • autoClose:读完后自动关闭,默认值为true

返回值

Readable的子类ReadStream

事件

通过返回值得到的ReadStream的绑定, .on(事件种类,函数)

open

文件打开事件,文件被打开时触发

1
2
3
4
5
6
7
8
9
10
11

const rs = fs.createReadStream(filename, {
encoding: 'utf-8',
highWaterMark: 1
})

// 文件打开事件

rs.on('open', () => {
console.log('文件被打开了!')
})
close

文件关闭后触发

文件关闭的两种方法:

  1. 可读流.close(); 手动关闭
  2. 文件读完后自动关闭
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

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指定的数量,回调函数中会附带读到的数据。

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
32
33
34
35
36
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

1
2
3
4
5
6
7
8
9
10
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);

手写,使用可读流和可写流

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
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

1
2
3
4
5
6
7
8
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('复制完成!');
});
})