NodeJS的Buffer模块进阶

附录:常用HTTP响应头和请求头信息对照表

  1. Node简介
  2. 第一个node程序
  3. module(模块系统)
  4. npm包管理器
  5. 模块系统优先级
  6. 认识http内置模块
  7. url内置模块
  8. path内置模块
  9. fs内置模块
  10. http模块服务端进阶
  11. http报文浅析
  12. url模块进阶
  13. path模块进阶
  14. querystring模块进阶
  15. 了解Buffer和Stream
  16. os模块
  17. Buffer模块
  18. Stream模块
  19. http模块客户端
  20. Cookie浅析

Buffer模块进阶

Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整。

Buffer 类在 Node.js 中是一个全局变量,因此无需使用 require('buffer').Buffer

Buffer 类

在计算机内使用二进制表示数据,一个存储空间叫做一个 bit ,只能存储 0 或是 1。 通常,计算机把 8 个bit作为一个存储的单位,称为一个 Byte。于是一个 Byte 可以出现 256 种不同的情况。

一个 Buffer 是一段内存,比如大小为 2(Byte)的buffer,一共有 16 bit ,比如是 00000001 00100011 ,可是这样显示太不方便。所以显示这段内存的数据的时候,用其对应的 16 进制就比较方便了,是 01 23,之所以用 16 进制是因为转换比较方便。

Buffer.alloc(size[, fill[, encoding]])
  • size 新建的 Buffer 期望的长度
  • fill <string> | <Buffer> | <integer> 用来预填充新建的 Buffer 的值。 默认: 0
  • encoding 如果 fill 是字符串,则该值是它的字符编码。 默认: 'utf8'

分配一个大小为 size 字节的新建的 Buffer 。 如果 fillundefined ,则该 Buffer 会用 0 填充

例子:

const buf = Buffer.alloc(5);
 
// 输出: <Buffer 00 00 00 00 00>
console.log(buf);

如果指定了 fill ,则会调用buf.fill(fill)初始化分配的 Buffer

例子:

const buf = Buffer.alloc(5, 'a');
 
// 输出: <Buffer 61 61 61 61 61>
console.log(buf);
 

如果同时指定了 fillencoding ,则会调用 buf.fill(fill, encoding) 初始化分配的 Buffer

Buffer.from(array)

通过一个八位字节的 array 创建一个新的 Buffer

例子:

// 创建一个新的包含字符串 'buffer' 的 UTF-8 字节的 Buffer
const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);

如果 array 不是一个数组,则抛出 TypeError 错误。

类方法:Buffer.from(buffer)

  • buffer 一个要拷贝数据的已存在的 Buffer

将传入的 buffer 数据拷贝到一个新建的 Buffer 实例。

例子:

const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1);
 
buf1[0] = 0x61;
 
// 输出: auffer
console.log(buf1.toString());
 
// 输出: buffer
console.log(buf2.toString());
 

如果 buffer 不是一个 Buffer,则抛出 TypeError 错误。

Buffer.from(string[, encoding])
  • string 要编码的字符串
  • encoding <string> 的字符编码。 默认: 'utf8'

新建一个包含所给的 JavaScript 字符串 stringBufferencoding 参数指定 string 的字符编码。

例子:

const buf1 = Buffer.from('this is a tést');
 
// 输出: this is a tést
console.log(buf1.toString());
 
// 输出: this is a tC)st
console.log(buf1.toString('ascii'));
 
 
const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
 
// 输出: this is a tést
console.log(buf2.toString());
 

如果 string 不是一个字符串,则抛出 TypeError 错误。

Buffer.isBuffer(obj)
  • 返回: 如果 obj 是一个 Buffer 则返回 true ,否则返回 false
Buffer.isEncoding(encoding)
  • encoding 一个要检查的字符编码名称
  • 返回: 如果 encoding 是一个支持的字符编码则返回 true,否则返回 false

Buffer 与字符编码

Buffer 实例一般用于表示编码字符的序列,比如 UTF-8 、 UCS2 、 Base64 、或十六进制编码的数据。 通过使用显式的字符编码,就可以在 Buffer 实例与普通的 JavaScript 字符串之间进行相互转换。

例子:

const buf = Buffer.from('hello world', 'ascii');
 
// 输出 68656c6c6f20776f726c64
console.log(buf.toString('hex'));
 
// 输出 aGVsbG8gd29ybGQ=
console.log(buf.toString('base64'));

Node.js 目前支持的字符编码包括:

  • 'ascii' - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。
  • 'utf8' - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
  • 'utf16le' - 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。
  • 'ucs2' - 'utf16le' 的别名。
  • 'base64' - Base64 编码。当从字符串创建 Buffer 时,按照 RFC4648 第 5 章的规定,这种编码也将正确地接受“URL 与文件名安全字母表”。
  • 'latin1' - 一种把 Buffer 编码成一字节编码的字符串的方式(由 IANA 定义在 RFC1345 第 63 页,用作 Latin-1 补充块与 C0/C1 控制码)。
  • 'binary' - 'latin1' 的别名。
  • 'hex' - 将每个字节编码为两个十六进制字符。

Buffer实例化对象

buf[index]

索引操作符 [index] 可用于获取或设置 buf 中指定 index 位置的八位字节。 这个值指向的是单个字节,所以合法的值范围是的 0x000xFF(十六进制),或 0255(十进制)。

例如:拷贝一个 ASCII 字符串到一个 Buffer,每次一个字节。

const str = 'Node.js';
const buf = Buffer.allocUnsafe(str.length);
 
for (let i = 0; i < str.length; i++) {
  buf[i] = str.charCodeAt(i);
}
 
// 输出: Node.js
console.log(buf.toString('ascii'));

buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])

  • target 要比较的 Buffer

  • targetStart target 中开始对比的偏移量。 默认: 0

  • targetEnd target 中结束对比的偏移量(不包含)。 当 targetStartundefined 时忽略。 默认: target.length

  • sourceStart buf 中开始对比的偏移量。 当 targetStartundefined 时忽略。 默认: 0

  • sourceEnd 中结束对比的偏移量(不包含)。 当 targetStartundefined 时忽略。 默认: buf.length

  • 返回: 比较 buftarget,返回表明 buf 在排序上是否排在 target 之前、或之后、或相同。 对比是基于各自 Buffer 实际的字节序列。

  • 如果 targetbuf 相同,则返回 0

  • 如果 target 排在 buf 前面,则返回 1

  • 如果 target 排在 buf 后面,则返回 -1

例子:

const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
const buf3 = Buffer.from('ABCD');
 
// 输出: 0
console.log(buf1.compare(buf1));
 
// 输出: -1
console.log(buf1.compare(buf2));
 
// 输出: -1
console.log(buf1.compare(buf3));
 
// 输出: 1
console.log(buf2.compare(buf1));
 
// 输出: 1
console.log(buf2.compare(buf3));
 
// 输出: [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
// (结果相当于: [buf1, buf3, buf2])
console.log([buf1, buf2, buf3].sort(Buffer.compare));
 

可选的 targetStarttargetEndsourceStartsourceEnd 参数可用于分别在 targetbuf 中限制对比在指定的范围内。

例子:

const buf1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
const buf2 = Buffer.from([5, 6, 7, 8, 9, 1, 2, 3, 4]);
 
// 输出: 0
console.log(buf1.compare(buf2, 5, 9, 0, 4));
 
// 输出: -1
console.log(buf1.compare(buf2, 0, 6, 4));
 
// 输出: 1
console.log(buf1.compare(buf2, 5, 6, 5));

如果 targetStart < 0sourceStart < 0targetEnd > target.byteLengthsourceEnd > source.byteLength,则抛出 RangeError 错误。

buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])

  • target 要拷贝进的 Buffer
  • targetStart target 中开始拷贝进的偏移量。 默认: 0
  • sourceStart buf 中开始拷贝的偏移量。 当 targetStartundefined 时忽略。 默认: 0
  • sourceEnd buf 中结束拷贝的偏移量(不包含)。 当 sourceStartundefined 时忽略。 默认: buf.length
  • 返回: 被拷贝的字节数。拷贝 buf 的一个区域的数据到 target 的一个区域,即便 target 的内存区域与 buf 的重叠。

例子:创建两个 Buffer 实例 buf1buf2 ,并拷贝 buf1 中第 16 个至第 19 个字节到 buf2 第 8 个字节起。

const buf1 = Buffer.allocUnsafe(26);
const buf2 = Buffer.allocUnsafe(26).fill('!');
 
for (let i = 0; i < 26; i++) {
  // 97 是 'a' 的十进制 ASCII 值
  buf1[i] = i + 97;
}
 
buf1.copy(buf2, 8, 16, 20);
 
// 输出: !!!!!!!!qrst!!!!!!!!!!!!!
console.log(buf2.toString('ascii', 0, 25));

例子:创建一个 Buffer ,并拷贝同一 Buffer 中一个区域的数据到另一个重叠的区域。

const buf = Buffer.allocUnsafe(26);
 
for (let i = 0; i < 26; i++) {
  // 97 是 'a' 的十进制 ASCII 值
  buf[i] = i + 97;
}
 
buf.copy(buf, 0, 4, 10);
 
// 输出: efghijghijklmnopqrstuvwxyz
console.log(buf.toString());
 

buf.equals(otherBuffer)

  • otherBuffer 要比较的 Buffer
  • 返回: 如果 bufotherBuffer 具有完全相同的字节,则返回 true,否则返回 false

例子:

const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex');
const buf3 = Buffer.from('ABCD');
 
// 输出: true
console.log(buf1.equals(buf2));
 
// 输出: false
console.log(buf1.equals(buf3));

buf.fill(value[, offset[, end]][, encoding])

  • value 用来填充 buf 的值。
  • offset 开始填充 buf 前要跳过的字节数。默认: 0
  • end 结束填充 buf 的位置(不包含)。默认: buf.length
  • encoding 如果 value 是一个字符串,则这是它的字符编码。默认: 'utf8'
  • 返回: buf 的引用。

如果未指定 offsetend,则填充整个 buf。 这个简化使得一个 Buffer 的创建与填充可以在一行内完成。

例子:用 ASCII 字符 'h' 填充 Buffer

const b = Buffer.allocUnsafe(50).fill('h');
 
// 输出: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
console.log(b.toString());
 

value 如果不是一个字符串或整数,则会被强行转换为 uint32 值。

如果 fill() 操作的最后一次写入的是一个多字节字符,则只有字符中适合 buf 的第一个字节会被写入。

例子:用一个两个字节的字符填充 Buffer

// 输出: <Buffer c8 a2 c8>
console.log(Buffer.allocUnsafe(3).fill('\u0222'));
 

buf.includes(value[, byteOffset][, encoding])

  • value 要搜索的值
  • byteOffset buf 中开始搜索的位置。默认: 0
  • encoding 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'
  • 返回: 如果 buf 找到 value,则返回 true,否则返回 false

相当于 buf.indexOf() !== -1

例子:

const buf = Buffer.from('this is a buffer');
 
// 输出: true
console.log(buf.includes('this'));
 
// 输出: true
console.log(buf.includes('is'));
 
// 输出: true
console.log(buf.includes(Buffer.from('a buffer')));
 
// 输出: true
// (97 是 'a' 的十进制 ASCII 值)
console.log(buf.includes(97));
 
// 输出: false
console.log(buf.includes(Buffer.from('a buffer example')));
 
// 输出: true
console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
 
// 输出: false
console.log(buf.includes('this', 4));

buf.indexOf(value[, byteOffset][, encoding])

  • value 要搜索的值
  • byteOffset buf 中开始搜索的位置。默认: 0
  • encoding 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'
  • 返回: bufvalue 首次出现的索引,如果 buf 没包含 value 则返回 -1

如果 value 是:

  • 字符串,则 value 根据 encoding 的字符编码进行解析。

  • Buffer ,则 value 会被作为一个整体使用。如果要比较部分 Buffer,可使用 buf.slice()

  • 数值, 则 value 会解析为一个 0255 之间的无符号八位整数值。

例子:

const buf = Buffer.from('this is a buffer');
 
// 输出: 0
console.log(buf.indexOf('this'));
 
// 输出: 2
console.log(buf.indexOf('is'));
 
// 输出: 8
console.log(buf.indexOf(Buffer.from('a buffer')));
 
// 输出: 8
// (97 是 'a' 的十进制 ASCII 值)
console.log(buf.indexOf(97));
 
// 输出: -1
console.log(buf.indexOf(Buffer.from('a buffer example')));
 
// 输出: 8
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
 
// 输出: 4
console.log(utf16Buffer.indexOf('\u03a3', 0, 'ucs2'));
 
// 输出: 6
console.log(utf16Buffer.indexOf('\u03a3', -4, 'ucs2'));

如果 value 不是一个字符串, 数字, 或者 Buffer, 该方法会抛出一个 TypeError 异常, 如果 value 是一个数字, 它将会被强制转换成一个有效的 byte 值, 该值介于0到255之间。

如果 byteOffset 不是一个数字, 它将会被强制转换成一个数字。 任何对 NaN or 0, like {}, [], null or undefined, 的参数, 将会搜索整个 buffer。 该行为和 String#indexOf() 保持一致。

const b = Buffer.from('abcdef');
 
// 传入一个不是有效字节的数字
// 输出:2,相当于搜索 99 或 'c'
console.log(b.indexOf(99.9));
console.log(b.indexOf(256 + 99));
 
// 传入 byteOffset,其值强制转换为 NaN 或 0
// 输出:1,搜索整个 buffer
console.log(b.indexOf('b', undefined));
console.log(b.indexOf('b', {}));
console.log(b.indexOf('b', null));
console.log(b.indexOf('b', []));
 

如果 value 是一个空字符串或空 Buffer,并且 byteOffset 小于 buf.length,返回 byteOffset。如果 value 是一个空字符串,并且 byteOffset 大于 buf.length,返回 buf.length

buf.keys()

创建并返回一个包含 buf 键名(索引)的迭代器

例子:

const buf = Buffer.from('buffer');
 
// 输出:
//   0
//   1
//   2
//   3
//   4
//   5
for (const key of buf.keys()) {
  console.log(key);
}
 

buf.values()

  • 返回: 创建并返回一个包含 buf 的值(字节)的迭代器。 当 Buffer 使用 for..of 时会自动调用该函数。

例子:

const buf = Buffer.from('buffer');
 
// 输出:
//   98
//   117
//   102
//   102
//   101
//   114
for (const value of buf.values()) {
  console.log(value);
}
 
// 输出:
//   98
//   117
//   102
//   102
//   101
//   114
for (const value of buf) {
  console.log(value);
}

buf.entries()

buf 的内容中,创建并返回一个 [index, byte] 形式的迭代器

例子:记录一个 Buffer 全部的内容。

const buf = Buffer.from('buffer');
 
// 输出:
//   [0, 98]
//   [1, 117]
//   [2, 102]
//   [3, 102]
//   [4, 101]
//   [5, 114]
for (const pair of buf.entries()) {
  console.log(pair);
}

buf.lastIndexOf(value[, byteOffset][, encoding])

  • value 要搜索的值
  • byteOffset buf 中开始搜索的位置。 默认: buf.length- 1
  • encoding 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'
  • 返回: bufvalue 最后一次出现的索引,如果 buf 没包含 value 则返回 -1

buf.indexOf() 类似,除了 buf 是从后往前搜索而不是从前往后。

例子:

const buf = Buffer.from('this buffer is a buffer');
 
// 输出: 0
console.log(buf.lastIndexOf('this'));
 
// 输出: 17
console.log(buf.lastIndexOf('buffer'));
 
// 输出: 17
console.log(buf.lastIndexOf(Buffer.from('buffer')));
 
// 输出: 15
// (97 是 'a' 的十进制 ASCII 值)
console.log(buf.lastIndexOf(97));
 
// 输出: -1
console.log(buf.lastIndexOf(Buffer.from('yolo')));
 
// 输出: 5
console.log(buf.lastIndexOf('buffer', 5));
 
// 输出: -1
console.log(buf.lastIndexOf('buffer', 4));
 
 
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
 
// 输出: 6
console.log(utf16Buffer.lastIndexOf('\u03a3', undefined, 'ucs2'));
 
// 输出: 4
console.log(utf16Buffer.lastIndexOf('\u03a3', -5, 'ucs2'));
 

如果 value 不是一个字符串, 数字, 或者 Buffer, 该方法会抛出一个 TypeError 异常, 如果 value 是一个数字, 它将会被强制转换成一个有效的 byte 值, 该值介于0到255之间。

如果 byteOffset 不是一个数字, 它将会被强制转换成一个数字。 任何对 NaN or 0, like {}, [], null or undefined, 的参数, 将会搜索整个 buffer。 该行为和 String#lastIndexOf() 保持一致。

const b = Buffer.from('abcdef');
 
// 传入一个不是有效字节的数字
// 输出:2,相当于搜索 99 或 'c'
console.log(b.lastIndexOf(99.9));
console.log(b.lastIndexOf(256 + 99));
 
// 传入 byteOffset,其值强制转换为 NaN
// 输出:1,搜索整个 buffer
console.log(b.lastIndexOf('b', undefined));
console.log(b.lastIndexOf('b', {}));
 
// 传入 byteOffset,其值强制转换为 0
// 输出:-1,相当于传入 0
console.log(b.lastIndexOf('b', null));
console.log(b.lastIndexOf('b', []));
 

如果 value 是一个空字符串或者空 Buffer,返回 byteOffset

buf.length

返回 buf 在字节数上分配的内存量。 注意,这并不一定反映 buf 内可用的数据量。

例子:创建一个 Buffer 并写入一个较短的 ASCII 字符串。

const buf = Buffer.alloc(1234);
 
// 输出: 1234
console.log(buf.length);
 
buf.write('some string', 0, 'ascii');
 
// 输出: 1234
console.log(buf.length);
 

虽然 length 属性不是不可变的,但改变 length 的值可能会导致不确定、不一致的行为。 那些希望修改一个 Buffer 的长度的应用程序应当将 length 视为只读的,且使用 buf.slice() 创建一个新的 Buffer

例子:

let buf = Buffer.allocUnsafe(10);
 
buf.write('abcdefghj', 0, 'ascii');
 
// 输出: 10
console.log(buf.length);
 
buf = buf.slice(0, 5);
 
// 输出: 5
console.log(buf.length);

buf.slice([start[, end]])

  • start 新建的 Buffer 开始的位置。 默认: 0
  • end 新建的 Buffer 结束的位置(不包含)。 默认: buf.length
  • 返回: 返回一个指向相同原始内存的新建的 Buffer,但做了偏移且通过 startend 索引进行裁剪。

指定负的索引会导致切片的生成是相对于 buf 的末尾而不是开头。

例子:

const buf = Buffer.from('buffer');
 
// 输出: buffe
// (相当于 buf.slice(0, 5))
console.log(buf.slice(-6, -1).toString());
 
// 输出: buff
// (相当于 buf.slice(0, 4))
console.log(buf.slice(-6, -2).toString());
 
// 输出: uff
// (相当于 buf.slice(1, 4))
console.log(buf.slice(-5, -2).toString());

buf.toJSON()

  • 返回: 返回 buf 的 JSON 格式。 当字符串化一个 Buffer 实例时,JSON.stringify() 会隐式地调用该函数。

例子:

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
 
// 输出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);
 
const copy = JSON.parse(json, (key, value) => {
  return value && value.type === 'Buffer' ?
    Buffer.from(value.data) :
    value;
});
 
// 输出: <Buffer 01 02 03 04 05>
console.log(copy);

buf.toString([encoding[, start[, end]]])

  • encoding 解码使用的字符编码。默认: 'utf8'
  • start 开始解码的字节偏移量。默认: 0
  • end 结束解码的字节偏移量(不包含)。 默认: buf.length
  • 返回: 根据 encoding 指定的字符编码解码 buf 成一个字符串。 startend 可传入用于只解码 buf 的一部分。

例子:

const buf1 = Buffer.allocUnsafe(26);
 
for (let i = 0; i < 26; i++) {
  // 97 是 'a' 的十进制 ASCII 值
  buf1[i] = i + 97;
}
 
// 输出: abcdefghijklmnopqrstuvwxyz
console.log(buf1.toString('ascii'));
 
// 输出: abcde
console.log(buf1.toString('ascii', 0, 5));
 
 
const buf2 = Buffer.from('tést');
 
// 输出: 74c3a97374
console.log(buf2.toString('hex'));
 
// 输出: té
console.log(buf2.toString('utf8', 0, 3));
 
// 输出: té
console.log(buf2.toString(undefined, 0, 3));
 

buf.write(string[, offset[, length]][, encoding])

  • string 要写入 buf 的字符串。
  • offset 开始写入 string 前要跳过的字节数。默认: 0
  • length 要写入的字节数。默认: buf.length - offset
  • encoding string 的字符编码。默认: 'utf8'
  • 返回: 写入的字节数。

根据 encoding 的字符编码写入 stringbuf 中的 offset 位置。 length 参数是写入的字节数。 如果 buf 没有足够的空间保存整个字符串,则只会写入 string 的一部分。 只部分解码的字符不会被写入。

例子:

const buf = Buffer.allocUnsafe(256);
 
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
 
// 输出: 12 个字节: ½ + ¼ = ¾
console.log(`${len} 个字节: ${buf.toString('utf8', 0, len)}`);

buffer.transcode(source, fromEnc, toEnc)

  • source 一个 Buffer 实例
  • fromEnc 当前编码
  • toEnc目标编码

将给定的 Buffer 实例从一个字符编码重新编码到另一个字符。 返回一个新的Buffer实例。

如果 fromEnctoEnc 指定的字符串编码无效,或者不允许从 fromEnc 转换为 toEnc,将抛出异常。

如果给定的字节序列不能在目标编码中充分表示,转码过程将使用替代字符。例如:

const buffer = require('buffer');
 
const newBuf = buffer.transcode(Buffer.from('€'), 'utf8', 'ascii');
console.log(newBuf.toString('ascii'));
// 输出: '?'

因为欧元符号()不能在 US-ASCII 中表示,所以在转换 Buffer 的时候使用 ? 代替。

注意 buffer 属性是通过 require('buffer') 返回的 buffer 模块,而不是全局 BufferBuffer 实例的属性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值