node中的可读流和可写流

javascript的一个不足之处是不能处理二进制数据,于是node中引入了Buffer类型。这个类型以一个字节(即8位)为单位,给数据分配存储空间。它的使用类似于Array,但是与Array又有不同:Buffer在定义的时候必须明确知道其长度,但是Array的长度是可以动态变化的。定义Buffer有三种方式:

1. var buf = new Buffer(3);//指定buffer占用3个字节

2. var buf = new Buffer("hello","utf-8");//指定了字符串,以及字符串的编码类型为utf-8,占用5个字节

3. var buf = new Buffer([256,255,2]);//定义了buffer的每个字节所存储的数字,最大为255,超过255取模

为什么介绍Buffer呢?因为本文所介绍的流就是以字节为单位传输的,而Buffer存储的就是字节。

Node中用fs模块的createReadStream和createWriteStream分别创建可读流和可写流。先介绍第一个接口。

一. createReadStream

这个方法继承了EventEmitter类,因而也可以发射和监听相关事件。其用法如下:

var rs = fs.createReadStream(filePath , {options});rs.on("data",function(data){console.log(data);});rs.on("end",function(data){console.log("resource file is completely read");});rs.on("error",function(err){console.log("something is wrong during processing");})

options是一组key-value值,常用的设置如下:

flags: 对文件进行何种操作,默认为‘r‘,读文件

encoding:指定编码,默认为null,如果不设置具体的编码格式,读出的数据就是Buffer类型;也可以使用rs.setEncoding("utf-8")指定编码格式

start:从start开始读取文件

end:读取文件到end为止(包括end)

highWaterMark:最高水位线,内部缓冲区最多能容纳的字节数,如果超过这个大小,就停止读取资源文件,默认值是64KB

前面几个设置就遵从字面意思,比较好理解。重点讲讲highWaterMark。

比如有一个100KB的文件,设置highWaterMark为10KB,那么系统会先从资源文件中读取出10KB的数据,再触发data事件;然后再读取10KB的数据,触发data事件,不断执行,直到读出了所有的数据,触发end事件。highWaterMark不能设置的过小,过小就会频繁的操作文件,影响性能。

可读流还有两个重要的方法:pause和resume,分别可以禁止发射data事件以及激活发射data事件。这两个方法稍后再讲解。

二.createWriteStream

和createReadStream一样,它也是EventEmitter的一个子类。它的drain事件在缓冲区数据写入完毕后被触发。

其用法举例:

var ws = fs.createWriteStream(filePath, {options});

其常用的options值为:

flags:对文件进行何种操作,默认为“w",代表写文件;如果是"a",代表每次写入的时候,不清空文件中的原有数据,而是直接在原有数据的末尾添加新数据

encoding:指定写入的编码格式,默认为null

start:文件开始写入的位置

highWaterMark:缓存区能够容纳的最大字节数,默认为16KB,如果超过这个值,write方法就会返回false

可写流的highWaterMark也代表了缓冲区的容量,如果缓冲区已经装满了,继续写入数据就会失败。只有等缓冲区里的内容被写入文件后,才可以重新调用write方法写入下一个highWaterMark大小的数据(data chunk)。

可写流也有两个重要的方法:write和end,write定义了写入的内容,end可以将还未写入的内容强行写入文件,并且关闭目标文件(不能继续写入了)。

基于以上分析,我们来实现一个文件拷贝的例子:

var fs=require("fs");
var rs = fs.createReadStream("./Koala.jpg");//默认64KB
var ws = fs.createWriteStream("./Copy.jpg");//默认16KB,写入速度小于读取速度
rs.on("data",function(data){
   var flag = ws.write(data);
    if (!flag){ //缓冲区已满
        rs.pause();//停止触发data事件
    }
});
ws.on("drain",function(){
    rs.resume();//如果当前的缓冲区写入完毕,就重新触发data事件
});
rs.on("end",function(){
    ws.end();//将剩下的数据全部写入,并且关闭写入的文件
})

这个例子综合运用了可读流和可写流的事件和重要方法。由于读流比写入流的速度快,所以要控制可读流的数据流动。通过控制data事件的触发时机,就解决了这个问题。

时间: 2024-11-09 05:09:27

node中的可读流和可写流的相关文章

node中的Readable - flowing/non-flowing mode

大家都知道在node中Readable Stream有两种模式: flowing mode和non-flowing mode. 对于flowing mode的Readable Stream, 我们是没法控制它何时去读数据读多少的,它会去尽快的去消耗data,并emit出来. 1 // in lib/_stream_readable.js 2 if (state.flowing && state.length === 0 &&!state.sync) { 3 stream.e

java中文件的读与写

最近一直在学习java中如何读取和写出文件,看了java API之后,发现在java.io中有很多关于文件读与写的类,下面就介绍几个经常用到的. 首先是:InputStream和OutputStream,API中说它俩是所有抽象类表示字节输入输出流的超类,所以在它们下面派生了很多子类.例如:FileInputStream和OutputStream等等.这些类都是以单字节的形式读入数据的,所以如果读入的数据中有中文字符,那么就会出现中文乱码现象. 其次是:Reader和Writer,这两个类是用于

java中关于编码的问题(字符转换流及字符缓冲流 )

上次我们使用的是字节流,还有一种方式就是字符流,上次说过如何分辨使用哪种流,如果记事本可以读懂则使用字符流,否则使用字节流.使用字符流就需要牵扯到编码的问题,下面给出一种转化流的格式. OutputStreamWriter OutputStreamWriter(OutputStream os):默认编码,GBK OutputStreamWriter(OutputStream os,String charsetName):指定编码.InputStreamReader InputStreamRead

【node】记录项目的开始与完成——pipeline_kafka流式数据库管理项目

前言: 我始终坚信的一点是,学习的效果80%来自总结,甚至全部都是.总结的好处就是让你能翻出你的过往,指出其中的不足,看到未来的改进方法,好的总结更能让知识产生飞跃,所以在工作之余,部署项目之际,总结一番. 架构处理: 一.背景 公司数据量庞大,万花筒一样的领导随即用上了pipeline_kafka这样的流式数据架构.其实在接手项目之前,作为一个应用开发.我是不太清楚kafka是什么鬼的,还有stream.transform.等等一系列名词,听起来很高大上,但是很懵比=-=. 领导的目标是做一个

Node系列——Node中的异常处理。

1.对异常错误的理解 异常错误应该被分为两种情况:操作失败和程序员失误 1.1.操作失败 这是正确编写的程序在运行时产生的错误.它并不是程序的Bug,反而经常是其它问题. 例如:系统本身(内存不足或者打开文件数过多),系统配置(没有到达远程主机的路由),网络问题(端口挂起),远程服务(500错误,连接失败).具体情况如下: 连接不到服务器 无法解析主机名 无效的用户输入 请求超时 服务器返回500 套接字被挂起 系统内存不足 1.2.程序员失误 这是程序里的Bug.这些错误往往可以在调试阶段通过

Node中的全局变量和全局对象

全局对象和全局变量 概念:所有属性都可以在程序的任何地方访问,即全局变量.在JavaScript中,通常window是全局对象,而Node.js的全局对象是global,所有全局变量都是global对象的属性,如:console.process等. global最根本的作用是作为全局变量的宿主,满足一下条件称为全局变量 1. 在最外层定义的变量 2. 全局对象的属性 3. 隐式定义的变量 ▲ 在node中不可能在最外层定义变量,因为所有的用户代码都是属于当前模块的,而模块本身是不属于最外层上下文

node中的常用核心模块及方法

常用的5个核心模块 http url querystring fs events 1. http http.createServer 创建服务器, 回调函数中有2个参数 1.req:request() 请求,只能在服务端看到 2.res:response() 给客户端的回复,在客户端看到 req参数: req.url 获取请求的地址 eg:http://www.baidu.com/api/list?a=23&b=f,则req.url为/api/list req.method 请求的方式get/p

node 中的 stream

什么是 stream Stream 借鉴自 Unix 编程哲学中的 pipe. Unix shell 命令中觉的管道流式操作 | 将上一个命令的输出作为下一个命令的输入.node stream 中则是通过 .pip() 方法来进行的. 一个 stream 的运用场景.从服务器读取文件并返回给页面. 朴素的实现: var http = require('http'); var fs = require('fs'); var server = http.createServer(function (

node 进阶 | 通过node中如何捕获异常阐述express的特点

node如何捕获异常 node基于js的单线程,有了非阻塞异步回调的概念,但是在处理多个并发连接时,并发环境要求高,最重要的是单线程,单核CPU,一个进程crash则web服务都crash,但是为什么node还这么火?甚至有了Node工程师这个岗,肯定就是node有自己crash之前与之后的解决方法,比如捕获异常 问:nodejs如何捕获异常?答:回调函数中有err形参,console.log出来,这是我之前回答别人问题的答案,但是自从我这几天看了如何捕获异常,才知道捕获异常的精髓就是不要让服务