内容简介:最近的几篇文章中都涉及到了
最近的几篇文章中都涉及到了 Buffer
, 虽然用过几个API, 还是系统总结一下, 主要针对API, 具体使用会少一点
为什么使用 Buffer
?
在引入 TypedArray 之前,JavaScript 语言没有用于读取或操作二进制数据流的机制。 Buffer 类是作为 Node.js API 的一部分引入的,用于在 TCP 流、文件系统操作、以及其他上下文中与八位字节流进行交互。
最常用的场景在于:
-
TCP流: 目前遇到用在封包和解包阶段, 提到的三篇文章中都有涉及WebSocket RPC
-
文件系统操作
参考
1. 创建Buffer
1.1 alloc家族
单纯创建大小为 size
字节的新Buffer
-
Buffer.alloc(size[, fill[, encoding]])-
分配的
buffer会通过buf.fill进行初始化, 能确保永远不会包含敏感数据 -
因为有初始化操作, 因此速度相较于
allocUnsafe慢得多
-
-
Buffer.allocUnsafe(size)-
分配的
buffer内存是未初始化的, 可能包含敏感数据
-
分配的
-
Buffer.allocUnsafeSlow(size)-
分配的
buffer内存是未初始化的, 可能包含敏感数据 -
创建一个非内存池的
buffer, 避免垃圾回收机制因创建太多独立的buffer而过度使用
-
三者选择:
// 需要一个全新的buffer Buffer.alloc // 需要一个buffer, 不在意有没有敏感数据, 反正都会被覆盖, 更常用 Buffer.allocUnsafe // 需要一个需要再内存池中保留的buffer Buffer.allocUnsafeSlow 复制代码
1.2 from五胞胎
-
Buffer.from(string[, encoding])-
从字符串创建一个
buffer, 是最常用的
-
从字符串创建一个
-
Buffer.from(buffer)-
从
buffer创建一个buffer, 常用于复制
-
从
-
Buffer.from(array)-
从数字数组常见一个
buffer, 如果不是数字, 自动被0填充
-
从数字数组常见一个
-
Buffer.from(arrayBuffer[, byteOffset[, length]]): 因为没用过, 记了也没价值 -
Buffer.from(object[, offsetOrEncoding[, length]])-
从对象创建一个
buffer, 实际类似于Buffer.from(string) -
本质上是调用对象的
Symbol.toPrimitive或valueOf方法
-
栗子1: Buffer.from(object)
class A {
[Symbol.toPrimitive]() {
return 'A'
}
}
Buffer.from(new A(), 'utf-8')
// 打印 <Buffer 41>
复制代码
栗子2: Buffer.from(array)
Buffer.from(['a', '1', 2, 'b', '3']) // 打印 <Buffer 00 01 02 00 03> 复制代码
2. Buffer的迭代
Buffer
实例可以使用 for..of
语法迭代, 相关的函数还有:
-
buf.keys() -
buf.values() -
buf.entries()
不过这样非常无聊
const buf = Buffer.from([1, 2, 3]);
for (const b of buf) {
console.log(b);
}
// 打印:
// 1
// 2
// 3
复制代码
索引操作符都比这有趣: 索引操作符 [index] 可用于获取或设置 buf 中指定位置的字节
const buf = Buffer.from('Calabash')
console.log(buf[0]) // 67
复制代码
3. 两个buffer间的碰撞
-
buf.compare- 主要用于 Buffer 数组的排序, 建议跳过
-
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])-
拷贝
buf中的某个区域的数据到target中的某个区域
-
拷贝
-
buf.equals(otherBuffer)-
比较两个
buffer是否具有完全相同的字节
-
比较两个
-
Buffer.concat(list[, totalLength])-
合并list中的
Buffer数组
-
合并list中的
4. BE和LE世家
4.1 大小端
考虑一个w位(bit)的整数,位表示为[Xw-1, Xw-2, ... ,X1, X0],其中Xw-1是最高有效位, 而X0是最低有效位。假设w是8的倍数,这些位就能被分组成为字节,其中最高有效字节包含位[Xw-1, Xw-2, ... ,Xw-8], 而最低有效字节包含位[X7, X6, ... ,Xw-8], 大小端指的就是有效字节的排列方式
-
小端法(little endian): 最低有效字节在最前面
-
大端法(big endian): 最高有效字节在最前面
大端 vs 小端对比
// 假设后面两个字节二进制值为 1111 1111 0000 0001 // 转为十六进制为 0xff 0x01 // 大端输出 65281 console.log(Buffer.from([0xff, 0x01]).readUInt16BE(0).toString(10)) // 小端输出 511 console.log(Buffer.from([0xff, 0x01]).readUInt16LE(0).toString(10)) 复制代码
TCP/IP为任意整数数据项定义了统一的网络字节顺序(network byte order):大端字节顺序
额外补充一点~
-
网络序就是大端法字节顺序
-
本地序依据机器类型,可能是大端法字节顺序或者小端法字节顺序
4.2 读/写字节流
读字节流一共22个API, 其中包含如下两个 只需要一个字节就能表示, 不涉及大小端 的API
-
buf.readInt8: 读取一个有符号的8位整数, 1个字节 -
buf.readUint8: 读取一个无符号的8位整数, 1个字节
其他的数字类型包括:
-
读取
BigInt类型, 8个字节:readBigInt64BE readBigInt64LE readBigUInt64BE readBigUInt64LE
-
读取64位双精度浮点数, 8个字节:
readDoubleBE readDoubleLE
-
读取32位浮点数, 4个字节:
readFloatBE readFloatLE
-
读取16位整数, 2个字节
readInt16BE readInt16LE readUInt16BE readUInt16LE
-
读取32位整数, 4个字节
readInt32BE readInt32LE readUInt32BE readUInt32LE
-
读取指定的字节数, 最高支持48位精度, 0~6个字节
readIntBE readIntLE readUIntBE readUIntLE
写字节流的API与上方一致, 只需要将 read
换成 write
4.3 交换大小端
一共涉及三个方法, 都会
将 buf
解析成无符号的x位整数的数组, 并以字节的顺序原地进行交换
-
swap16():buf.length必须是2的倍数 -
swap32():buf.length必须是4的倍数 -
swap64():buf.length必须是8的倍数
例如:
// 65281 Buffer.from([0xff, 0x01]).readUInt16BE(0).toString(10) // 511 Buffer.from([0xff, 0x01]).readUInt16LE(0).toString(10) // 511 Buffer.from([0xff, 0x01]).swap16().readUInt16BE(0).toString(10) 复制代码
5. 小甜点
-
buf.toJSON: 返回buf的JSON格式, 当字符串化Buffer时,JSON.stringify()会调用该函数
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
console.log(json);
// 打印: {"type":"Buffer","data":[1,2,3,4,5]}
复制代码
-
buf.slice(start, end): 创建一个指向与原始Buffer同一内存得新Buffer, 但进行了裁剪, 注意两个对象所分配的内存是重叠的, 修改一个会影响另一个 -
base64和string的转换
// Y2FsYWJhc2g=
const base64Str = Buffer.from('calabash').toString('base64')
// calabash
Buffer.from(base64Str, 'base64').toString()
复制代码
6. END
到这里基本完成 Buffer API
的学习, 不过以我目前的水平, 没有需要自己封包解包的场景, 只有看别人封包解包了TAT
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Nginx中常用的模块整理
- 月薪 50K 大牛整理!六大Java架构进阶技术模块,看完茅塞顿开!
- web系列之模块化——AMD、CMD、CommonJS、ES6 整理&&比较
- 照片整理系列二 —— 照片整理及归档的辛酸历程
- 我自己整理的码农周刊一周分享整理
- 【复习资料】ES6/ES7/ES8/ES9资料整理(个人整理)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Usability for the Web
Tom Brinck、Darren Gergle、Scott D. Wood / Morgan Kaufmann / 2001-10-15 / USD 65.95
Every stage in the design of a new web site is an opportunity to meet or miss deadlines and budgetary goals. Every stage is an opportunity to boost or undercut the site's usability. Thi......一起来看看 《Usability for the Web》 这本书的介绍吧!