源代码: 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);
// 打印: 16
const { 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
// 3
const { 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,则创