js 字节数组转数字以及数字转字节数组
javascript通过ArrayBuffer和DataView实现字节数组和数字之间的相互转换
注意!我这里的所有函数用的都是大端字节序(高位在前,低位在后),即数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中
举例:2个字节的无符号整型1的二进制表示
大端模式: 0000 0000 0000 0001
小端模式: 0000 0001 0000 0000
如果字节序不一致,解析的数据就会出错!如果你的数据是小端模式,就需要翻转数组,或者重写这些函数,DataView的setInt32和getInt32之类的函数可以传入一个参数来控制大端还是小端,我采用的是默认的情况下的大端模式
具体代码如下
test(); function test() { var bytes = getFloat64Bytes(-3.33); alert(bytes); alert(toFloat64(bytes)); } //构建一个视图,把字节数组写到缓存中,索引从0开始,大端字节序 function getView(bytes) { var view = new DataView(new ArrayBuffer(bytes.length)); for (var i = 0; i < bytes.length; i++) { view.setUint8(i, bytes[i]); } return view; } //将字节数组转成有符号的8位整型,大端字节序 function toInt8(bytes) { return getView(bytes).getInt8(); } //将字节数组转成无符号的8位整型,大端字节序 function toUint8(bytes) { return getView(bytes).getUint8(); } //将字节数组转成有符号的16位整型,大端字节序 function toInt16(bytes) { return getView(bytes).getInt16(); } //将字节数组转成无符号的16位整型,大端字节序 function toUint16(bytes) { return getView(bytes).getUint16(); } //将字节数组转成有符号的32位整型,大端字节序 function toInt32(bytes) { return getView(bytes).getInt32(); } //将字节数组转成无符号的32位整型,大端字节序 function toUint32(bytes) { return getView(bytes).getUint32(); } //将字节数组转成32位浮点型,大端字节序 function toFloat32(bytes) { return getView(bytes).getFloat32(); } //将字节数组转成64位浮点型,大端字节序 function toFloat64(bytes) { return getView(bytes).getFloat64(); } //将数值写入到视图中,获得其字节数组,大端字节序 function getUint8Array(len, setNum) { var buffer = new ArrayBuffer(len); //指定字节长度 setNum(new DataView(buffer)); //根据不同的类型调用不同的函数来写入数值 return new Uint8Array(buffer); //创建一个字节数组,从缓存中拿取数据 } //得到一个8位有符号整型的字节数组,大端字节序 function getInt8Bytes(num) { return getUint8Array(1, function (view) { view.setInt8(0, num); }) } //得到一个8位无符号整型的字节数组,大端字节序 function getUint8Bytes(num) { return getUint8Array(1, function (view) { view.setUint8(0, num); }) } //得到一个16位有符号整型的字节数组,大端字节序 function getInt16Bytes(num) { return getUint8Array(2, function (view) { view.setInt16(0, num); }) } //得到一个16位无符号整型的字节数组,大端字节序 function getUint16Bytes(num) { return getUint8Array(2, function (view) { view.setUint16(0, num); }) } //得到一个32位有符号整型的字节数组,大端字节序 function getInt32Bytes(num) { return getUint8Array(4, function (view) { view.setInt32(0, num); }) } //得到一个32位无符号整型的字节数组,大端字节序 function getUint32Bytes(num) { return getUint8Array(4, function (view) { view.setUint32(0, num); }) } //得到一个32位浮点型的字节数组,大端字节序 function getFloat32Bytes(num) { return getUint8Array(4, function (view) { view.setFloat32(0, num); }) } //得到一个64位浮点型的字节数组,大端字节序 function getFloat64Bytes(num) { return getUint8Array(8, function (view) { view.setFloat64(0, num); }) } ////下面几个为另一种实现方式的版本,只实现了简单几种,其他的实现起来比较麻烦,所以就中途放弃了 //function toInt32(bytes) { // return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF); //} //function toUInt16(bytes) { // return ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF); //} //function toInt16(bytes) { // return bytes[0] >> 7 == 0 ? toUInt16(bytes) : toUInt16(bytes) - 65536; //} //function getInt32Bytes(num) { // return [num >> 24 & 0xFF, num >> 16 & 0xFF, num >> 8 & 0xFF, num & 0xFF]; //} //function getUint16Bytes(num) { // return [num >> 8 & 0xFF, num & 0xFF]; //} //function getInt16Bytes(num) { // return num >= 0 ? getUint16Bytes(num) : getUint16Bytes(65536 + num); //}
还有个小问题,我这边数字转字节数组函数的返回值都是Uint8Array,这是一个TypeArray类型,它和Array不是一个东西,定长的,不能push,而且Array.concat无法正常连接Uint8Array数组(会将Uint8Array整体作为一个对象),如果使用的是Array,就需要自己处理下,或者直接在getUint8Array函数中将Uint8Array转成Array
//将数值写入到视图中,获得其字节数组,大端字节序 function getUint8Array(len, setNum) { var buffer = new ArrayBuffer(len); //指定字节长度 setNum(new DataView(buffer)); //根据不同的类型调用不同的函数来写入数值 var uint8Array = new Uint8Array(buffer); //创建一个字节数组,从缓存中拿取数据 var arr = new Array(); //将Uint8Array转成Array数组,不考虑性能问题 for (var i = 0; i < uint8Array.byteLength; i++) { //尴尬,Uint8Array没有length,只有byteLength,之前写的竟然没测就发布了,现在才发现问题 arr.push(uint8Array[i]); } return arr; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)