源代码: lib/buffer.js
Buffer 对象用于表示固定长度的字节序列。
许多 Node.js API 都支持 Buffer。
Buffer 类是 JavaScript Uint8Array 类的子类,并使用涵盖额外用例的方法对其进行扩展。
Node.js API 在支持 Buffer 的地方也接受普通的 Uint8Array。
虽然 Buffer 类在全局作用域内可用,但仍然建议通过 import 或 require 语句显式地引用它。
import { Buffer } from 'buffer';
// 创建长度为 10 的以零填充的缓冲区。
const buf1 = Buffer.alloc(10);
// 创建长度为 10 的缓冲区,
// 使用值为 `1` 的字节填充。
const buf2 = Buffer.alloc(10, 1);
// 创建长度为 10 的未初始化的缓冲区。
// 这比调用 Buffer.alloc() 快,
// 但返回的缓冲区实例可能包含旧数据,
// 需要使用 fill()、write() 、
// 或其他填充缓冲区内容的函数重写。
const buf3 = Buffer.allocUnsafe(10);
// 创建包含字节 [1, 2, 3] 的缓冲区。
const buf4 = Buffer.from([1, 2, 3]);
// 创建包含字节 [1, 1, 1, 1] 的缓冲区,
// 所有条目都使用 `(value & 255)` 截断以符合范围 0–255。
const buf5 = Buffer.from([257, 257.5, -255, '1']);
// 创建包含字符串 'tést' 的 UTF-8 编码字节的缓冲区:
// [0x74, 0xc3, 0xa9, 0x73, 0x74](十六进制)
// [116, 195, 169, 115, 116](十进制)
const buf6 = Buffer.from('tést');
// 创建包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的缓冲区。
const buf7 = Buffer.from('tést', 'latin1');const { Buffer } = require('buffer');
// 创建长度为 10 的以零填充的缓冲区。
const buf1 = Buffer.alloc(10);
// 创建长度为 10 的缓冲区,
// 使用值为 `1` 的字节填充。
const buf2 = Buffer.alloc(10, 1);
// 创建长度为 10 的未初始化的缓冲区。
// 这比调用 Buffer.alloc() 快,
// 但返回的缓冲区实例可能包含旧数据,
// 需要使用 fill()、write() 、
// 或其他填充缓冲区内容的函数重写。
const buf3 = Buffer.allocUnsafe(10);
// 创建包含字节 [1, 2, 3] 的缓冲区。
const buf4 = Buffer.from([1, 2, 3]);
// 创建包含字节 [1, 1, 1, 1] 的缓冲区,
// 所有条目都使用 `(value & 255)` 截断以符合范围 0–255。
const buf5 = Buffer.from([257, 257.5, -255, '1']);
// 创建包含字符串 'tést' 的 UTF-8 编码字节的缓冲区:
// [0x74, 0xc3, 0xa9, 0x73, 0x74](十六进制)
// [116, 195, 169, 115, 116](十进制)
const buf6 = Buffer.from('tést');
// 创建包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的缓冲区。
const buf7 = Buffer.from('tést', 'latin1');
当在 Buffer 和字符串之间进行转换时,可以指定字符编码。
如果未指定字符编码,则默认使用 UTF-8。
import { Buffer } from 'buffer';
const buf = Buffer.from('hello world', 'utf8');
console.log(buf.toString('hex'));
// 打印: 68656c6c6f20776f726c64
console.log(buf.toString('base64'));
// 打印: aGVsbG8gd29ybGQ=
console.log(Buffer.from('fhqwhgads', 'utf8'));
// 打印: <Buffer 66 68 71 77 68 67 61 64 73>
console.log(Buffer.from('fhqwhgads', 'utf16le'));
// 打印: <Buffer 66 00 68 00 71 00 77 00 68 00 67 00 61 00 64 00 73 00>const { Buffer } = require('buffer');
const buf = Buffer.from('hello world', 'utf8');
console.log(buf.toString('hex'));
// 打印: 68656c6c6f20776f726c64
console.log(buf.toString('base64'));
// 打印: aGVsbG8gd29ybGQ=
console.log(Buffer.from('fhqwhgads', 'utf8'));
// 打印: <Buffer 66 68 71 77 68 67 61 64 73>
console.log(Buffer.from('fhqwhgads', 'utf16le'));
// 打印: <Buffer 66 00 68 00 71 00 77 00 68 00 67 00 61 00 64 00 73 00>
Node.js 缓冲区接受它们接收到的编码字符串的所有大小写变体。
例如,UTF-8 可以指定为 'utf8'、'UTF8' 或 'uTf8'。
Node.js 目前支持的字符编码如下:
'utf8'(别名:'utf-8'):多字节编码的 Unicode 字符。
许多网页和其他文档格式使用 UTF-8。
这是默认的字符编码。
当将 Buffer 解码为不完全包含有效 UTF-8 数据的字符串时,则 Unicode 替换字符 U+FFFD � 将用于表示这些错误。
'utf16le'(别名:'utf-16le'):多字节编码的 Unicode 字符。
与 'utf8' 不同,字符串中的每个字符都将使用 2 或 4 个字节进行编码。
Node.js 仅支持 UTF-16 的小端序变体。
'latin1': Latin-1 代表 ISO-8859-1。
此字符编码仅支持 U+0000 至 U+00FF 的 Unicode 字符。
每个字符都使用单个字节进行编码。
不符合该范围的字符将被截断并映射到该范围内的字符。
使用以上编码之一将 Buffer 转换为字符串称为解码,将字符串转换为 Buffer 称为编码。
Node.js 还支持以下二进制转文本的编码。
对于二进制转文本的编码,命名约定是相反的:将 Buffer 转换为字符串通常称为编码,将字符串转换为 Buffer 通常称为解码。
'base64': Base64 编码。
当从字符串创建 Buffer 时,此编码还将正确接受 RFC 4648,第 5 节中指定的 "URL 和文件名安全字母表"。
base64 编码的字符串中包含的空白字符(例如空格、制表符和换行符)会被忽略。
'base64url': base64url 编码如 RFC 4648 第 5 节中指定。
当从字符串创建 Buffer 时,此编码也将正确接受常规的 base64 编码的字符串。
当将 Buffer 编码为字符串时,此编码将忽略填充。
'hex': 将每个字节编码为两个十六进制字符。
当解码不完全由偶数个十六进制字符组成的字符串时,可能会发生数据截断。
请参阅下面的示例。
还支持以下旧版字符编码:
'ascii': 仅适用于 7 位 ASCII 数据。
当将字符串编码为 Buffer 时,这等效于使用 'latin1'。
当将 Buffer 解码为字符串时,使用此编码将在解码为 'latin1' 之前额外取消设置每个字节的最高位。
通常,没有理由使用此编码,因为在编码或解码纯 ASCII 文本时,'utf8'(或者,如果已知数据始终是纯 ASCII,则为 'latin1')将是更好的选择。
它仅用于旧版兼容性。
'binary': 'latin1' 的别名。
有关此主题的更多背景信息,请参阅二进制字符串。
此编码的名称很容易让人误解,因为这里列出的所有编码都在字符串和二进制数据之间进行转换。
对于字符串和 Buffer 之间的转换,通常 'utf8' 是正确的选择。
'ucs2', 'ucs-2': 'utf16le' 的别名。
UCS-2 过去指的是 UTF-16 的一种变体,它不支持代码点大于 U+FFFF 的字符。
在 Node.js 中,始终支持这些代码点。
import { Buffer } from 'buffer';
Buffer.from('1ag123', 'hex');
// 打印 <Buffer 1a>,当遇到第一个非十六进制值 ('g') 时,则截断数据。
Buffer.from('1a7', 'hex');
// 打印 <Buffer 1a>,当数据以一位数 ('7') 结尾时,则截断数据。
Buffer.from('1634', 'hex');
// 打印 <Buffer 16 34>,表现所有数据。const { Buffer } = require('buffer');
Buffer.from('1ag123', 'hex');
// 打印 <Buffer 1a>,当遇到第一个非十六进制值 ('g') 时,则截断数据。
Buffer.from('1a7', 'hex');
// 打印 <Buffer 1a>,当数据以一位数 ('7') 结尾时,则截断数据。
Buffer.from('1634', 'hex');
// 打印 <Buffer 16 34>,表现所有数据。
现代 Web 浏览器遵循 WHATWG 编码标准,其将 'latin1' 和 'ISO-8859-1' 别名为 'win-1252'。
这意味着在执行 http.get() 之类的操作时,如果返回的字符集是 WHATWG 规范中列出的字符集之一,则服务器实际上可能返回 'win-1252' 编码的数据,使用 'latin1' 编码可能会错误地解码字符。
Buffer 实例也是 JavaScript Uint8Array 和 TypedArray 实例。
所有 TypedArray 方法都可在 Buffer 上使用。
但是,Buffer API 和 TypedArray API 之间存在细微的不兼容。
特别是:
TypedArray.prototype.slice() 创建 TypedArray 部分的副本,而 Buffer.prototype.slice() 在现有 Buffer 上创建视图而不进行复制。
这种行为可能会有意外,并且仅存在于旧版兼容性中。
TypedArray.prototype.subarray() 可用于在 Buffer 和其他 TypedArray 上实现 Buffer.prototype.slice() 的行为。buf.toString() 与其对应的 TypedArray 不兼容。buf.indexOf(),支持额外的参数。有两种方式可以从 Buffer 创建新的 TypedArray 实例:
Buffer 传给 TypedArray 构造函数将复制 Buffer 的内容,解释为整数数组,而不是目标类型的字节序列。import { Buffer } from 'buffer';
const buf = Buffer.from([1, 2, 3, 4]);
const uint32array = new Uint32Array(buf);
console.log(uint32array);
// 打印: Uint32Array(4) [ 1, 2, 3, 4 ]const { Buffer } = require('buffer');
const buf = Buffer.from([1, 2, 3, 4]);
const uint32array = new Uint32Array(buf);
console.log(uint32array);
// 打印: Uint32Array(4) [ 1, 2, 3, 4 ]
ArrayBuffer 底层的 Buffer 将创建与 Buffer 共享其内存的 TypedArray。import { Buffer } from 'buffer';
const buf = Buffer.from('hello', 'utf16le');
const uint16array = new Uint16Array(
buf.buffer,
buf.byteOffset,
buf.length / Uint16Array.BYTES_PER_ELEMENT);
console.log(uint16array);
// 打印: Uint16Array(5) [ 104, 101, 108, 108, 111 ]const { Buffer } = require('buffer');
const buf = Buffer.from('hello', 'utf16le');
const uint16array = new Uint16Array(
buf.buffer,
buf.byteOffset,
buf.length / Uint16Array.BYTES_PER_ELEMENT);
console.log(uint16array);
// 打印: Uint16Array(5) [ 104, 101, 108, 108, 111 ]
通过以相同的方式使用 TypedArray 对象的 .buffer 属性,可以创建新的 Buffer,它与 TypedArray 实例共享相同的分配内存。
Buffer.from() 在这种情况下表现得像 new Uint8Array()。
import { Buffer } from 'buffer';
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// 复制 `arr` 的内容。
const buf1 = Buffer.from(arr);
// 与 `arr` 共享内存。
const buf2 = Buffer.from(arr.buffer);
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer 88 13 a0 0f>
arr[1] = 6000;
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer 88 13 70 17>const { Buffer } = require('buffer');
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// 复制 `arr` 的内容。
const buf1 = Buffer.from(arr);
// 与 `arr` 共享内存。
const buf2 = Buffer.from(arr.buffer);
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer 88 13 a0 0f>
arr[1] = 6000;
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer 88 13 70 17>
使用 TypedArray 的 .buffer 创建 Buffer 时,可以通过传入 byteOffset 和 length 参数仅使用底层 ArrayBuffer 的一部分。
import { Buffer } from 'buffer';
const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
console.log(buf.length);
// 打印: 16const { Buffer } = require('buffer');
const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
console.log(buf.length);
// 打印: 16
Buffer.from() 和 TypedArray.from() 具有不同的签名和实现。
具体来说,TypedArray 变体接受第二个参数,该参数是在类型化数组的每个元素上调用的映射函数:
TypedArray.from(source[, mapFn[, thisArg]])但是,Buffer.from() 方法不支持使用映射函数:
可以使用 for..of 语法迭代 Buffer 实例:
import { Buffer } from 'buffer';
const buf = Buffer.from([1, 2, 3]);
for (const b of buf) {
console.log(b);
}
// 打印:
// 1
// 2
// 3const { Buffer } = require('buffer');
const buf = Buffer.from([1, 2, 3]);
for (const b of buf) {
console.log(b);
}
// 打印:
// 1
// 2
// 3
此外,buf.values()、buf.keys() 和 buf.entries() 方法可用于创建迭代器。
Blob 类#Blob 封装了不可变的原始数据,可以在多个工作线程之间安全地共享。
new buffer.Blob([sources[, options]])#sources <string[]> | <ArrayBuffer[]> | <TypedArray[]> | <DataView[]> | <Blob[]> 将存储在 Blob 中的字符串数组、<ArrayBuffer>、<TypedArray>、<DataView> 或 <Blob> 对象、或此类对象的任何组合。options <Object>
创建新的 Blob 对象,其中包含给定源的串接。
<ArrayBuffer>、<TypedArray>、<DataView> 和 <Buffer> 源被复制到 'Blob' 中,因此可以在创建 'Blob' 后安全地修改。
字符串源被编码为 UTF-8 字节序列并复制到 Blob 中。 每个字符串部分中不匹配的代理对将被 Unicode U+FFFD 替换字符替换。
blob.arrayBuffer()#返回使用包含 Blob 数据副本的 <ArrayBuffer> 履行的 promise。
blob.size#Blob 的总大小(以字节为单位)。
blob.slice([start, [end, [type]]])#创建并返回包含此 Blob 对象数据子集的新 Blob。
原 Blob 没有改动。
blob.stream()#返回允许读取 Blob 内容的新 ReadableStream。
blob.text()#返回使用解码为 UTF-8 字符串的 Blob 的内容履行的 promise。
blob.type#Blob 的内容类型。
一旦创建了 <Blob> 对象,就可以通过 MessagePort 将其发送到多个目的地,而无需传输或立即复制数据。
只有在调用 arrayBuffer() 或 text() 方法时才会复制 Blob 包含的数据。
import { Blob, Buffer } from 'buffer';
import { setTimeout as delay } from 'timers/promises';
const blob = new Blob(['hello there']);
const mc1 = new MessageChannel();
const mc2 = new MessageChannel();
mc1.port1.onmessage = async ({ data }) => {
console.log(await data.arrayBuffer());
mc1.port1.close();
};
mc2.port1.onmessage = async ({ data }) => {
await delay(1000);
console.log(await data.arrayBuffer());
mc2.port1.close();
};
mc1.port2.postMessage(blob);
mc2.port2.postMessage(blob);
// 发布后 Blob 仍然可用。
blob.text().then(console.log);const { Blob, Buffer } = require('buffer');
const { setTimeout: delay } = require('timers/promises');
const blob = new Blob(['hello there']);
const mc1 = new MessageChannel();
const mc2 = new MessageChannel();
mc1.port1.onmessage = async ({ data }) => {
console.log(await data.arrayBuffer());
mc1.port1.close();
};
mc2.port1.onmessage = async ({ data }) => {
await delay(1000);
console.log(await data.arrayBuffer());
mc2.port1.close();
};
mc1.port2.postMessage(blob);
mc2.port2.postMessage(blob);
// 发布后 Blob 仍然可用。
blob.text().then(console.log);
Buffer 类#Buffer 类是直接处理二进制数据的全局类型。
它可以使用多种方式构建。
Buffer.alloc(size[, fill[, encoding]])#size <integer> 新的 Buffer 所需的长度。fill <string> | <Buffer> | <Uint8Array> | <integer> 用于预填充新 Buffer 的值。 默认值: 0。encoding <string> 如果 fill 是字符串,则这就是它的编码。
默认值: 'utf8'。分配 size 个字节的新 Buffer。
如果 fill 为 undefined,则 Buffer 将以零填充。
import { Buffer } from 'buffer';
const buf = Buffer.alloc(5);
console.log(buf);
// 打印: <Buffer 00 00 00 00 00>const { Buffer } = require('buffer');
const buf = Buffer.alloc(5);
console.log(buf);
// 打印: <Buffer 00 00 00 00 00>
如果 size 大于 buffer.constants.MAX_LENGTH 或小于 0,则抛出 ERR_INVALID_ARG_VALUE。
如果指定了 fill,则分配的 Buffer 将通过调用 buf.fill(fill) 进行初始化。
import { Buffer } from 'buffer';
const buf = Buffer.alloc(5, 'a');
console.log(buf);
// 打印: <Buffer 61 61 61 61 61>const { Buffer } = require('buffer');
const buf = Buffer.alloc(5, 'a');
console.log(buf);
// 打印: <Buffer 61 61 61 61 61>
如果同时指定了 fill 和 encoding,则分配的 Buffer 将通过调用 buf.fill(fill, encoding) 进行初始化。
import { Buffer } from 'buffer';
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
console.log(buf);
// 打印: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>const { Buffer } = require('buffer');
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
console.log(buf);
// 打印: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
调用 Buffer.alloc() 可能比替代的 Buffer.allocUnsafe() 慢得多,但可确保新创建的 Buffer 实例的内容永远不会包含来自先前分配的敏感数据,包括可能尚未分配给 Buffer 的数据。
如果 size 不是数值,则会抛出 TypeError。
Buffer.allocUnsafe(size)#size <integer> 新的 Buffer 所需的长度。分配 size 个字节的新 Buffer。
如果 size 大于 buffer.constants.MAX_LENGTH 或小于 0,则抛出 ERR_INVALID_ARG_VALUE。
以这种方式创建的 Buffer 实例的底层内存不会被初始化。
新创建的 Buffer 的内容是未知的,可能包含敏感的数据。
使用 Buffer.alloc() 来用零初始化 Buffer 实例。
import { Buffer } from 'buffer';
const buf = Buffer.allocUnsafe(10);
console.log(buf);
// 打印(内容可能会有所不同): <Buffer a0 8b 28 3f 01 00 00 00 50 32>
buf.fill(0);
console.log(buf);
// 打印: <Buffer 00 00 00 00 00 00 00 00 00 00>const { Buffer } = require('buffer');
const buf = Buffer.allocUnsafe(10);
console.log(buf);
// 打印(内容可能会有所不同): <Buffer a0 8b 28 3f 01 00 00 00 50 32>
buf.fill(0);
console.log(buf);
// 打印: <Buffer 00 00 00 00 00 00 00 00 00 00>
如果 size 不是数值,则会抛出 TypeError。
Buffer 模块预先分配了大小为 Buffer.poolSize 的内部 Buffer 实例作为池,用于快速分配使用 Buffer.allocUnsafe()、Buffer.from(array)、Buffer.concat() 创建的新 Buffer 实例,仅当 size 小于或等于 Buffer.poolSize >> 1(Buffer.poolSize 除以二再向下取整)时才使用弃用的 new Buffer(size) 构造函数。
使用此预先分配的内部内存池是调用 Buffer.alloc(size, fill) 与调用 Buffer.alloc(size, fill) 之间的关键区别。
具体来说,Buffer.alloc(size, fill) 永远不会使用内部的 Buffer 池,而 Buffer.allocUnsafe(size).fill(fill) 会在 size 小于或等于 Buffer.poolSize 的一半时使用内部的 Buffer 池。
当应用程序需要 Buffer.allocUnsafe() 提供的额外性能时,差异很细微,但可能很重要。
Buffer.allocUnsafeSlow(size)#size <integer> 新的 Buffer 所需的长度。分配 size 个字节的新 Buffer。
如果 size 大于 buffer.constants.MAX_LENGTH 或小于 0,则抛出 ERR_INVALID_ARG_VALUE。
如果 size 为 0,则创