stream 
什么是 Stream(小溪、小河,在编程中通常翻译为流)呢?
- 我们的第一反应应该是
流水,源源不断的流动; - 程序中的流也是
类似的含义,我们可以想象当我们从一个文件中读取数据时,文件的二进制(字节)数据会源源不断的被读取到我们程序中; - 而
这个一连串的字节,就是我们程序中的流; 
所以,我们可以这样理解流:
- 是
连续字节的一种表现形式和抽象概念; - 流应该是
可读的,也是可写的; 
在之前学习文件的读写时,我们可以直接通过 readFile 或者 writeFile 方式读写文件,为什么还需要流呢?
- 直接读
写文件的方式,虽然简单,但是无法控制一些细节的操作; - 比如从
什么位置开始读、读到什么位置、一次性读取多少个字节; - 读到
某个位置后,暂停读取,某个时刻恢复继续读取等等; - 或者这个
文件非常大,比如一个视频文件,一次性全部读取并不合适; 
事实上 Node 中很多对象是基于流实现的:
http模块的Request和Response对象;
官方文档:另外所有的流都是 EventEmitter 的实例。
那么在 Node 中都有哪些流呢?
Node.js 中有四种基本流类型:
Writable:可以向其写入数据的流(例如fs.createWriteStream())。Readable:可以从中读取数据的流(例如fs.createReadStream())。Duplex:同时为 Readable 和 Writable(例如 net.Socket)。Transform:Duplex可以在写入和读取数据时修改或转换数据的流(例如zlib.createDeflate())。
这里我们通过 fs 的操作,讲解一下 Writable、Readable,另外两个大家可以自行学习一下。
基本使用 
js
const fs = require('fs')
// 通过流读取文件
// 1.创建一个可读流
// start: 从什么位置开始读取
// end: 读取到什么位置后结束(包括end位置字节)
// highWaterMark:一次性读取字节的长度,默认是64kb;
const readStream = fs.createReadStream('./aaa.txt', {
  start: 8,
  end: 22,
  highWaterMark: 3,
})
readStream.on('data', (data) => {
  console.log(data.toString())
  // 关闭流
  readStream.pause()
  setTimeout(() => {
    // 打开流
    readStream.resume()
  }, 2000)
})可读流其他事件 
js
const fs = require('fs')
// 1.通过流读取文件
const readStream = fs.createReadStream('./aaa.txt', {
  start: 8,
  end: 22,
  highWaterMark: 3,
})
// 2.监听读取到的数据
readStream.on('data', (data) => {
  console.log(data.toString())
})
// 3.补充其他的事件监听
readStream.on('open', (fd) => {
  console.log('通过流将文件打开~', fd)
})
readStream.on('end', () => {
  console.log('已经读取到end位置')
})
readStream.on('close', () => {
  console.log('文件读取结束, 并且被关闭')
})可写流使用过程 
js
const fs = require('fs')
// 1.一次性写入内容
fs.writeFile(
  './bbb.txt',
  'hello world',
  {
    encoding: 'utf-8',
    flag: 'a+',
  },
  (err) => {
    console.log('写入文件结果:', err)
  }
)
// 2.创建一个写入流
const writeStream = fs.createWriteStream('./ccc.txt', {
  flags: 'a',
})
writeStream.on('open', (fd) => {
  console.log('文件被打开', fd)
})
writeStream.write('coderwhy')
writeStream.write('aaaa')
writeStream.write('bbbb', (err) => {
  console.log('写入完成:', err)
})
writeStream.on('finish', () => {
  console.log('写入完成了')
})
writeStream.on('close', () => {
  console.log('文件被关闭~')
})
// 3.写入完成时, 需要手动去掉用close方法
writeStream.close()
// 4.end方法:
// 操作一: 将最后的内容写入到文件中, 并且关闭文件
// 操作二: 关闭文件
writeStream.end('哈哈哈哈')文件的拷贝流 
js
const fs = require('fs')
// 1.方式一: 一次性读取和写入文件
fs.readFile('./foo.txt', (err, data) => {
  console.log(data)
  fs.writeFile('./foo_copy01.txt', data, (err) => {
    console.log('写入文件完成', err)
  })
})
// 2.方式二: 创建可读流和可写流
const readStream = fs.createReadStream('./foo.txt')
const writeStream = fs.createWriteStream('./foo_copy02.txt')
readStream.on('data', (data) => {
  writeStream.write(data)
})
readStream.on('end', () => [writeStream.close()])
// 3.在可读流和可写流之间建立一个管道
const readStream = fs.createReadStream('./foo.txt')
const writeStream = fs.createWriteStream('./foo_copy03.txt')
readStream.pipe(writeStream)