理解node中的Buffer

先上文档连接buffer缓冲器html

背景

在node应用程序中,咱们须要处理网络协议,文件流数据等,在网络流与文件的操做中,还有二进制数据。js中的string明显不能知足这些需求。而buffer对象为咱们提供了操做二进制流数据的能力。node

在引入 TypedArray 以前,JavaScript 语言没有用于读取或操做二进制数据流的机制。 Buffer 类是做为 Node.js API 的一部分引入的,用于在 TCP 流、文件系统操做、以及其余上下文中与八位字节流进行交互。
Buffer 类的实例相似于从 0 到 255 之间的整数数组(其余整数会经过 & 255 操做强制转换到此范围),但对应于 V8 堆外部的固定大小的原始内存分配。 Buffer 的大小在建立时肯定,且没法更改。
Buffer 类在全局做用域中,所以无需使用 require('buffer').Buffer。 --- 摘自文档git

Buffer简介

简单的介绍一下Buffer,它的元素为16进制的两位数(即10进制的0-255之间),以下图 github

危险的Buffer构造函数

值得注意的是,在node中,new Buffer('xxx')Buffer('xxx')由于存在着安全性问题,在v6的时候就被废弃了。因此咱们须要使用Buffer.from或者Buffer.alloc 来替代。这里建议启用ESLint规则no-buffer-constructornode/no-deprecated-api以免意外的不安全Buffer API使用。
那么,Buffer构造函数有什么问题吗?
原来,在node V8以前,new Buffer(50)将占有50个字节,假如这个做为CGI接受用户的输入,输入500000000,会占用500MB的内存,这么大的内存占用,很快就会内存溢出,致使服务崩溃。而现有的Buffer.from(5000000000)将会抛出异常。api

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type number
复制代码

内存的分配

Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现的内存的申请。当进行小而频繁的Buffer操做时,采用slab(一种动态内存管理的机制)机制进行预先申请和过后分配,使得js到操做系统直接没有过多的内存申请的系统调用。对于大Buffer而言,则是直接使用C++层面提供的内存,无需细腻的分配操做。(区别大小Buffer的界限为8Kb)数组

Buffer转换

可转换类型

Buffer对象可与字符串之间相互转换。支持的类型以下:浏览器

  • 'ascii': 仅适用于 7 位 ASCII 数据。此编码速度很快,若是设置则会剥离高位。安全

  • 'utf8': 多字节编码的 Unicode 字符。许多网页和其余文档格式都使用 UTF-8。bash

  • 'utf16le': 2 或 4 个字节,小端序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。markdown

  • 'ucs2': 'utf16le' 的别名。

  • 'base64': Base64 编码。当从字符串建立 Buffer 时,此编码也会正确地接受 RFC 4648 第 5 节中指定的 “URL 和文件名安全字母”。

  • 'latin1': 一种将 Buffer 编码成单字节编码字符串的方法(由 RFC 1345 中的 IANA 定义,第 63 页,做为 Latin-1 的补充块和 C0/C1 控制码)。

  • 'binary': 'latin1' 的别名。

  • 'hex': 将每一个字节编码成两个十六进制的字符。

如何转换

如下是一个Buffer对象与字符串相互转换的例子

const buf = Buffer.from('hello world', 'ascii');
console.log(buf.toString('hex'));
// 打印: 68656c6c6f20776f726c64
console.log(buf.toString('base64'));
// 打印: aGVsbG8gd29ybGQ=
复制代码

不支持的类型及处理方式

现有的编码那么多,Buffer只提供了几种,而Buffer.isEncoding则为咱们提供了编码是否支持转换的能力。对于不支持的类型,咱们只能借助额外的模块来解决了。例如iconv和iconv-lite

应用场景

I/O操做

const fs = require('fs');
const inputStream = fs.createReadStream('input.txt'); // 建立可读流
const outputStream = fs.createWriteStream('output.txt'); // 建立可写流
inputStream.pipe(outputStream); // 管道读写
复制代码

zlib.js

zlib.js 为 Node.js 的核心库之一,其利用了缓冲区(Buffer)的功能来操做二进制数据流,提供了压缩或解压功能。参考源代码 zlib.js 源码

var http = require('http');
var zlib = require('zlib');
var fs = require('fs');
var filepath = './extra/fileForGzip.html';

var server = http.createServer(function(req, res){
    var acceptEncoding = req.headers['accept-encoding'];
    var gzip;

    if(acceptEncoding.indexOf('gzip')!=-1){    // 判断是否须要gzip压缩

        gzip = zlib.createGzip();

        // 记得响应 Content-Encoding,告诉浏览器:文件被 gzip 压缩过
        res.writeHead(200, {
            'Content-Encoding': 'gzip'
        });
        fs.createReadStream(filepath).pipe(gzip).pipe(res);

    }else{

        fs.createReadStream(filepath).pipe(res);
    }

});

server.listen('3000');
复制代码

总结

Buffer在node中有着极其重要的地位,流数据的处理都离不开它。在使用时咱们用Buffer.from取代了new Buffer。Buffer的内存分配用到了slab机制进行预先申请和过后分配。在性能上,buffer比string有着更加优异的表现,缘由是流数据自己就是二进制数据,不须要作额外的转换就能够传输。

Reference

相关文章
相关标签/搜索