程序员人生 网站导航

Node核心模块之Stream

栏目:php教程时间:2017-02-23 09:21:39

Node核心模块之Stream

Node.js V6.9.4
流(stream)在node中是1个用于处理流数据的抽象接口,node中很对对象都是基于流的,如HTTP服务器,process.stdout要求
流是可读、可写的,或既可读有可写,并且所有流都是EventEmitter的实例
流主要用于实现1个copy方法

* const stream = require(‘stream’) *
1.流的4种类型

  • Readable: 可以读取数据的流
  • Writable: 可以写数据的流
  • Duplex: 既可以读数据的流,有可以写数据的流
  • Transform: 可以在写入和读取数据时修改或转换数据的双工流

2.buffer
* 可读流和可写流都将数据存储在内部缓冲区buffer中,当调用stream.push(chunk)时,数据被缓冲在可读流中,如果用户没有调用stream.read()读取流,那末在缓冲区中的流将会被1直存储 *
* 如果读缓冲区区中的buffer到达指定大小,则再次读取的流将不会被缓存,stream.write()也1样,1旦到达阈值,将返回false *
* stream.pipe()方法很好的解决上面的阈值问题, pipe()的目的在于将数据的缓冲限制在可接受的水平,被称为管道*

3.1个Node.js官网例子

const http = require('http');

const server = http.createServer( (req, res) => {
  // req is an http.IncomingMessage, which is a Readable Stream
  // res is an http.ServerResponse, which is a Writable Stream

  let body = '';
  // Get the data as utf8 strings.
  // If an encoding is not set, Buffer objects will be received.
  req.setEncoding('utf8');

  // Readable streams emit 'data' events once a listener is added
  req.on('data', (chunk) => {
    body += chunk;
  });

  // the end event indicates that the entire body has been received
  req.on('end', () => {
    try {
      const data = JSON.parse(body);
      // write back something interesting to the user:
      res.write(typeof data);
      res.end();
    } catch (er) {
      // uh oh!  bad json!
      res.statusCode = 400;
      return res.end(`error: ${er.message}`);
    }
  });
});

server.listen(1337);

// $ curl localhost:1337 -d '{}'
// object
// $ curl localhost:1337 -d '"foo"'
// string
// $ curl localhost:1337 -d 'not json'
// error: Unexpected token o

* 上例中: 可写流(res)暴露方法(write()、end()),这两个方法被用于将数据写入流中,可读流使用EventEmitter来通知利用程序什么时候可以读取流中的数据 *

4.可写流
* 可写流实际上是1块地方,就是寄存读取的数据的地方,或可以说内存 *

// 新建可写流: 方法1
const Writable = require('stream').Writable;

class MyWritable extends Writable {
  constructor(options) {
    // Calls the stream.Writable() constructor
    super(options);
  }
}

// 新建可写流: 方法2
const Writable = require('stream').Writable;
const util = require('util');

function MyWritable(options) {
  if (!(this instanceof MyWritable))
    return new MyWritable(options);
  Writable.call(this, options);
}
util.inherits(MyWritable, Writable);


// 新建可写流: 方法3
const Writable = require('stream').Writable;

const myWritable = new Writable({
  write(chunk, encoding, callback) {   // write方法为必须
    // ...
  },
  writev(chunks, callback) {
    // ...
  }
});

常见的可写流

  • HTTP requests, on the client
  • HTTP response, on the server
  • fs write streams
  • zlib streams
  • crypto streams
  • TCP sockets
  • child process stdin
  • process.stdout, process.stderr

    5.可读流
    * 可读流是读取数据源的抽象,即数据寄存的地方,或说内存 *

 // 新建可读流:方法1
const Readable = require('stream').Readable;

class MyReadable extends Readable {
  constructor(options) {
    // Calls the stream.Readable(options) constructor
    super(options);
  }
}


 // 新建可读流:方法2
const Readable = require('stream').Readable;
const util = require('util');

function MyReadable(options) {
  if (!(this instanceof MyReadable))
    return new MyReadable(options);
  Readable.call(this, options);
}
util.inherits(MyReadable, Readable);


 // 新建可读流:方法3
const Readable = require('stream').Readable;

const myReadable = new Readable({
  read(size) {   //异步方法
    // ...
  }

  push(chunk[,encoding]) //将数据chunk放进可读流队列里面
});

常见的可写流

  • HTTP response, on the client
  • HTTP request, on the server
  • fs read streams
  • zlib streams
  • crypto streams
  • TCP sockets
  • child process stdout and stderr
  • child process stdout and stderr
  • process.stdin

6.流的利用
* 对小文件,可使用可读流讲数据存在内存中,然后用可写流讲数据读取 *

const fs = require('fs');

var src = fs.readFileSync('/home/clx/old.sql');
fs.writeFileSync('/home/clx/new.sql', src);    // 在/home/clx目录下会出现1个new.sql文件

* 上面的例子中当old.sql不大时没有问题,但是当old.sql变成1部电影或几个G的’动作片’,那程序就会崩溃,有两种方法解决:1种是利用可读流暂停,1种是利用pipe管道 *

7.管道
** readable.pipe()将Writable流附加到可读流,使其自动切换到写流模式,并将其所有数据推送到附加的Writable。管道将自动管理流数据,使得当可读流大于可写流时数据不被丢失,或内存被过量的占用,
即管道是1边读1遍写 **

const fs = require('fs');
const Readable = require('stream').stream;

let readable = new Readable({
    read(size) {        //为可写流添加read方法,可读流必须有该方法
        this.push('/home/clx/old.mp4');
    }
});

const writable = fs.createWriteStream('/home/clx/new.mp4');


// 管道读写,结束后在/home/clx/目录下生成new.mp4文件

readable.pipe(writable, {end: false});      // => 管道读写完后触发读写流'end'事件

readable.on('end', () => {      // => 为读写流注册'end'事件
    write.end('End');
})

* Node.js很多方法都是基于流的,只是被封装好了,我们看不见,流是很多利用的基础,主要用来处理2进制文件 *

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐