【译】Node.js Buffers 完整指南
在 Node.js 中,buffers 是一个可以存储二进制数据的特殊类型。buffer 代表内存块-通常指在计算机中分配的 RAW 。buffer 的大小是不能更改的。
buffer 存储字节。八位(Bits)序列称为一个字节(byte)。位(Bits)在计算机中是最基本的存储单元,他们可以保存 0 或 1 的数值。
译者注:计算机是存储二进制数据的,二进制主要是 0 和 1 的集合。
Node.js 在全局作用域中可直接使用 Buffer 类(不需要像其他模块一样导入)。使用这个 API,你可以获取一系列函数和抽象来操作原始的二进制文件。
一个 buffer 在 Node.js 中就如以下表示:
在示例中,你可以看到 10 对字母和数字的组成,每一对表示存储在缓冲区中的字节,这个缓冲区的总大小为 10。
你可能会问自己:“如果这些是位和字节,那 0 和 1 在哪里呢?”
那是因为 Node.js 使用十六进制系统显示字节。这样,每个字节都可以仅使用两位数表示(一对数字和字母是从 0-9 和 "a" to "f")
为什么需要 buffers?因为在 buffers 出现之前,在 JavaScript 中并没有简单的方式去处理二进制数据,你必须采用类似于字符串的primitives
,这种方式是比较慢的,也没有专门的工具来处理二进制文件。所以 Buffers 会被创建,且提供一些简单和高效的 API 可以操作位和字节。
buffers 使用
让我们看看使用 buffers 可以做的一些事情。
你会注意到使用 buffer 有点类似于 JavaScript 中使用数组的方式。例如,你可以使用.slice()
,concat()
和 .length
操作 buffer。 缓冲区也是可迭代的,可以使用例如for-of
之类的构造器迭代。
如果你是在计算机上操作示例,记住 Buffer
类是全局的。你不需要单独的引入。
译者注: 虽然 Buffer 类在全局作用域内可用,但仍然建议通过 import 或 require 语句显式地引用它
创建 buffers
有三种方法创建 Buffers。
Buffer.from()
Buffer.alloc()
Buffer.allocUnsafe()
buffers 在以前是使用 Buffer 类构造函数(例如,new Buffer() )创建的。此语法已被弃用。
Buffer.from()
使用buffer.from()
是创建 buffer 的最直接方法。它可接受字符串、数组、ArrayBuffer
,或也可以是另一个 buffer 实例。根据传递的参数, Buffer.from()
将以不同的方式创建缓冲区。
传入字符串时,将创建一个包含该字符串的新缓冲区对象。默认情况下,它将使用 utf-8 作为编码解析你的输入(点击here查看支持的所有编码类型)
你还可以将字节数组传给Buffer.from()
。这里,我传入跟之前相同的字符串("heya!"),但是使用十六进制的字符数组表示。
如果你不熟悉0xNN
语法,则意味着 0x
之后的字符应该解释为十六进制值。
将 buffer 实例传入 Buffer.from()
时,Node.js 会复制该实例到当前的缓冲区中。由于新缓冲区会分配在不同的内存区域中,故你可以独立的修改它。
这些应该覆盖了你使用 Buffer.from()
的大多数情况。详情可参考文档 docs
Buffer.alloc()
.alloc()
方法在您想要创建空缓冲区时很有用,不需要初始化数据填充。默认情况下,它接受一个数字并返回一个给定大小并且填充了 0 的缓冲区。
你可以在之后填充你想要的任何数据。
你还可以使用 0 以外的其他内容和给定的编码填充缓冲区。
Buffer.allocUnsafe()
使用 .allocUnsafe()
,可以跳过清理和用 0 填充 buffer 的过程。 buffer 将被分配在可能包含旧数据的内存区域中(这就是“Unsafe”的部分来源)。例如,以下代码很可能每次运行时都会打印一些随机数据
.allocUnsafe()
有一个好处的使用情况是当你复制一个被安全分配的缓冲区。由于你复制 buffer 时是会完整的覆盖,所以所有旧字节数据都将被可预测的数据替换:
通常来说,.allocUnsafe()
应当仅被使用在你有很好的理由使用的情况下(例如,性能优化)使用。每当使用它时,请确保永远不在没有使用新数据填充完整它的情况下返回 buffer 实例,否则你可能会泄漏敏感的信息。
写入 buffers
Buffer.write()
是将数据写入 buffers 的方法。 默认情况下,它将写入一个以 utf-8
编码的、没有偏移(从 buffer 的第一个位置开始写入)的字符串。它会返回一个数字,是写入 buffer 中的字节数。
请记住,并非所有字符都会占用 buffer 中的单个字节 !
另外请注意到,2 不是字符拥有最大的字节数。例如,utf-8
编码类型支持最多 4 字节的字符。 由于无法修改缓冲区的大小,所以始终需要注意你正在编写的内容它将会占用多少空间(缓冲区的大小与内容的大小)。
另一个写入 buffer 的方法是通过类似于数组的语法 add
方法,把字节添加到 buffer 的特殊位置。需要注意的是,任何超过 1 个字节的数据都需要分解并设置在 buffer 的每个位置
虽然你可以使用类似数组的语法写入 buffers,但我建议你尽可能坚持使用 Buffer.from()
。管理输入的长度是一项艰巨的任务,并且会给你的代码带来复杂性。使用 .from()
,您可以无担忧的在 buffer 中写入内容,并通过检查是否未写入任何内容(返回 0 时)来处理输入过大的情况。
迭代 buffers
你可以使用类似于数组的现代 JavaScript 结构去迭代 buffer。例如: 使用 for-of
其他的遍历方法 例如 .entries()
, .values()
和 .keys()
也同样也适用于 buffers,栗子:使用 .entries()
走的更远: Buffers and TypeArrays
在 JavaScript(我的意思是一般的 JavaScript,不限于 Node.js)中,可以使用特殊的 ArrayBuffer 类分配内存。我们很少直接操作 ArrayBuffer 对象。相反,我们使用一组引用底层数组缓冲区的“视图”对象。这些视图对象是:
Int8Array
, Uint8Array
, Uint8ClampedArray
, Int16Array
, Uint16Array
, Int32Array
等。
完整列表 请点击here
这些上面列出的视图对象统称为TypedArray
。所有视图对象都通过原型从 TypedArray 继承方法。 TypedArray 构造函数不是全局公开的,必须始终使用其中一种视图方法。如果你看到一些使用 new TypedArray() 的教程或文档,这意味着它正在使用任何视图对象(Uint8Array、Float64Array 等)
在 Node.js 中,从 Buffer 类创建的对象也是 Uint8Array 的实例。它们之间有一些小的差异。你可以在此阅读 here
总结
作为初学者,buffers 是 Node.js 中的一个主题,让我感到非常困惑(另一个是流,但它值得拥有自己的帖子)。希望我能够揭开有关缓冲区的一些概念的神秘面纱,并概述 Buffer API。
我是废材壶,前端开发者,欢迎微信搜一搜「 CodeLife 集」阅读不迷路
评论