复合视图
var buffer = new ArrayBuffer(24);
var idView = new Uint32Array(buffer, 0, 1);
var usernameView = new Uint8Array(buffer, 4, 16);
var amountDueView = new Float32Array(buffer, 20, 1);
Int8Array uint16Array Int32Array 定义数据类型
无符号整型数组(取值范围)
var arr=new Uint8Array([85, 15, 0, 70, 3, 2, 39, 0, 17, 102, 0, 75, 0, 13, 165]);
// 二进制转 16进制
arr[0].toString(16)
arr[1].toString(16)
[[Int8Array]]: Int8Array(20) [90, 10, 3, 16, 5, 2, 15, 33, 59, -21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[[Int16Array]]: Int16Array(10) [2650, 4099, 517, 8463, -5317, 0, 0, 0, 0, 0]
[[Int32Array]]: Int32Array(5) [268634714, 554631685, 60219, 0, 0]
[[Uint8Array]]: Uint8Array(20) [90, 10, 3, 16, 5, 2, 15, 33, 59, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
byteLength: (...)
__proto__: ArrayBuffer
[[IsDetached]]: false
二进制内存 转十六进制 进行解读
function ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
ab2hex([90, 10, 3, 16, 5, 2, 15, 33, 59, -21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
"5a 0a 03 10 05 02 0f 21 3b eb 00000000000000000000"
//转码 // 5A 0A 03 10 05 02 0F 21 3B EB 十六进制转二进制 setUint8 写入内存
function hexStringToArrayBuffer(str) {
if (!str) {
return new ArrayBuffer(0);
}
var buffer = new ArrayBuffer(str.length);
let dataView = new DataView(buffer)
let ind = 0;
for (var i = 0, len = str.length; i < len; i += 2) {
let code = parseInt(str.substr(i, 2), 16)
dataView.setUint8(ind, code)
ind++
}
return buffer;
}
hexStringToArrayBuffer('5A0A031005020F213BEB')
[[Int8Array]]: Int8Array(20) [90, 10, 3, 16, 5, 2, 15, 33, 59, -21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[[Int16Array]]: Int16Array(10) [2650, 4099, 517, 8463, -5317, 0, 0, 0, 0, 0]
[[Int32Array]]: Int32Array(5) [268634714, 554631685, 60219, 0, 0]
[[Uint8Array]]: Uint8Array(20) [90, 10, 3, 16, 5, 2, 15, 33, 59, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
byteLength: (...)
__proto__: ArrayBuffer
[[IsDetached]]: false
03Int8Array Int16Array Int32Array
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
// 数组中每个元素的大小(以字节为单位)。
// 语法
// JavaScript
// var arraySize = uint16Array.BYTES_PER_ELEMENT
// var int32 = new Int32Array(3);//int32数组 3表示占位符几个 开辟内存中
// console.log(int32) //数组对象
// int32[0] = 42; //数组第一位数赋值
// console.log(int32[0]); // 42 读取第一位数数组
// console.log(int32.length); // 3 数组长度
// console.log(int32.BYTES_PER_ELEMENT); // 4个字节
// // 1字节(Byte,缩写为B)由8个位组成,即1Byte=8bit,是存储器的基本单位,通常被作为一个存储单元。通常情况下,把B称为字节
// // 1汉字=2字节1字节(Byte)=8字位=8个二进制数1字位(bit)=1个二进制数1B=8b1KB
// var int16 = new Int16Array(3)
// console.log(int16);
// int16[0] = 42;
// console.log(int16[0])
// console.log(int16.length)
// console.log(int16.BYTES_PER_ELEMENT)
// var int8 = new Int8Array(3)
// console.log(int8);
// int8[0] = 42;
// console.log(int8[0])
// console.log(int8.length)
// console.log(int8.BYTES_PER_ELEMENT)
//数组转化成视图数组
// var int8 = new Int8Array([1, 2]) //映射到内存中
// console.log(int8);
// console.log(int8[0])
// console.log(int8.length)
// console.log(int8.BYTES_PER_ELEMENT)
// //试图数组转化普通数组
// var normalArray = Array.apply([], int8);
// console.log(normalArray)
// var b = new ArrayBuffer(8);
// // (3)byteLength属性和byteOffset属性
// // byteLength属性返回类型化数组占据的内存长度,单位为字节。byteOffset属性返回类型化数组从底层ArrayBuffer对象的哪个字节开始。这两个属性都是只读属性。
// var v1 = new Int32Array(b);
// var v2 = new Uint8Array(b, 2);
// var v3 = new Int16Array(b, 2, 2);
// v1.byteLength // 8
// v2.byteLength // 6
// v3.byteLength // 4
// v1.byteOffset // 0
// v2.byteOffset // 2
// v3.byteOffset // 2
// // 注意将byteLength属性和length属性区分,前者是字节长度,后者是成员长度。
// var a = new Int16Array(8);
// a.length // 8
// a.byteLength // 16
// var iterable = function* () { yield* [1, 2, 3]; }();
// var int32 = new Int32Array(iterable);
// console.log(int32)
// Int32Array[1, 2, 3]
//完整的资料 https://blog.csdn.net/lichwei1983/article/details/43893025
// 视图的操作
// 建立了视图以后,就可以进行各种操作了。这里需要明确的是,视图其实就是普通数组,语法完全没有什么不同,只不过它直接针对内存进行操作,而且每个成员都有确定的数据类型。所以,视图就被叫做“类型化数组”。
// (1)数组操作
// 普通数组的操作方法和属性,对类型化数组完全适用。
// var buffer = new ArrayBuffer(16);
// var int32View = new Int32Array(buffer);
// for (var i = 0; i < int32View.length; i++) {
// int32View[i] = i * 2;
// }
// 上面代码生成一个16字节的ArrayBuffer对象,然后在它的基础上,建立了一个32位整数的视图。由于每个32位整数占据4个字节,所以一共可以写入4个整数,依次为0,2,4,6。
// 如果在这段数据上接着建立一个16位整数的视图,则可以读出完全不一样的结果。
// var int16View = new Int16Array(buffer);
// for (var i = 0; i < int16View.length; i++) {
// console.log("Entry " + i + ": " + int16View[i]);
// }
// // Entry 0: 0
// // Entry 1: 0
// // Entry 2: 2
// // Entry 3: 0
// // Entry 4: 4
// // Entry 5: 0
// // Entry 6: 6
// // Entry 7: 0
// 由于每个16位整数占据2个字节,所以整个ArrayBuffer对象现在分成8段。然后,由于x86体系的计算机都采用小端字节序(little endian),相对重要的字节排在后面的内存地址,相对不重要字节排在前面的内存地址,所以就得到了上面的结果。
// 比如,一个占据四个字节的16进制数0x12345678,决定其大小的最重要的字节是“12”,最不重要的是“78”。小端字节序将最不重要的字节排在前面,储存顺序就是78563412;大端字节序则完全相反,将最重要的字节排在前面,储存顺序就是12345678。目前,所有个人电脑几乎都是小端字节序,所以类型化数组内部也采用小端字节序读写数据,或者更准确的说,按照本机操作系统设定的字节序读写数据。
// 这并不意味大端字节序不重要,事实上,很多网络设备和特定的操作系统采用的是大端字节序。这就带来一个严重的问题:如果一段数据是大端字节序,类型化数组将无法正确解析,因为它只能处理小端字节序!为了解决这个问题,JavaScript引入DataView对象,可以设定字节序,下文会详细介绍。
// 下面是另一个例子。
// // 假定某段buffer包含如下字节 [0x02, 0x01, 0x03, 0x07]
// // 计算机采用小端字节序
// var uInt16View = new Uint16Array(buffer);
// // 比较运算
// if (bufView[0] === 258) {
// console.log("ok");
// }
// // 赋值运算
// uInt16View[0] = 255; // 字节变为[0xFF, 0x00, 0x03, 0x07]
// uInt16View[0] = 0xff05; // 字节变为[0x05, 0xFF, 0x03, 0x07]
// uInt16View[1] = 0x0210; // 字节变为[0x05, 0xFF, 0x10, 0x02]
// 总之,与普通数组相比,类型化数组的最大优点就是可以直接操作内存,不需要数据类型转换,所以速度快得多。
// (2)buffer属性
// 类型化数组的buffer属性,返回整段内存区域对应的ArrayBuffer对象。该属性为只读属性。
// var a = new Float32Array(64);
// var b = new Uint8Array(a.buffer);
// 上面代码的a对象和b对象,对应同一个ArrayBuffer对象,即同一段内存。
// (3)byteLength属性和byteOffset属性
// byteLength属性返回类型化数组占据的内存长度,单位为字节。byteOffset属性返回类型化数组从底层ArrayBuffer对象的哪个字节开始。这两个属性都是只读属性。
// var b = new ArrayBuffer(8);
// var v1 = new Int32Array(b);
// var v2 = new Uint8Array(b, 2);
// var v3 = new Int16Array(b, 2, 2);
// v1.byteLength // 8
// v2.byteLength // 6
// v3.byteLength // 4
// v1.byteOffset // 0
// v2.byteOffset // 2
// v3.byteOffset // 2
// 注意将byteLength属性和length属性区分,前者是字节长度,后者是成员长度。
// var a = new Int16Array(8);
// a.length // 8
// a.byteLength // 16
// (4)set方法
// 类型化数组的set方法用于复制数组,也就是将一段内容完全复制到另一段内存。
// var a = new Uint8Array(8);
// var b = new Uint8Array(8);
// b.set(a);
// 上面代码复制a数组的内容到b数组,它是整段内存的复制,比一个个拷贝成员的那种复制快得多。set方法还可以接受第二个参数,表示从b对象哪一个成员开始复制a对象。
// var a = new Uint16Array(8);
// var b = new Uint16Array(10);
// b.set(a, 2)
// 上面代码的b数组比a数组多两个成员,所以从b[2]开始复制。
// (5)subarray方法
// subarray方法是对于类型化数组的一部分,再建立一个新的视图。
// var a = new Uint16Array(8);
// var b = a.subarray(2, 3);
// a.byteLength // 16
// b.byteLength // 2
// subarray方法的第一个参数是起始的成员序号,第二个参数是结束的成员序号(不含该成员),如果省略则包含剩余的全部成员。所以,上面代码的a.subarray(2, 3) ,意味着b只包含a[2]一个成员,字节长度为2。
// (6)ArrayBuffer与字符串的互相转换
// ArrayBuffer转为字符串,或者字符串转为ArrayBuffer,有一个前提,即字符串的编码方法是确定的。假定字符串采用UTF - 16编码(JavaScript的内部编码方式),可以自己编写转换函数。
// // ArrayBuffer转为字符串,参数为ArrayBuffer对象
// function ab2str(buf) {
// return String.fromCharCode.apply(null, new Uint16Array(buf));
// }
// // 字符串转为ArrayBuffer对象,参数为字符串
// function str2ab(str) {
// var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
// var bufView = new Uint16Array(buf);
// for (var i = 0, strLen = str.length; i < strLen; i++) {
// bufView[i] = str.charCodeAt(i);
// }
// return buf;
// }
// 复合视图
// 由于视图的构造函数可以指定起始位置和长度,所以在同一段内存之中,可以依次存放不同类型的数据,这叫做“复合视图”。
// var buffer = new ArrayBuffer(24);
// var idView = new Uint32Array(buffer, 0, 1);
// var usernameView = new Uint8Array(buffer, 4, 16);
// var amountDueView = new Float32Array(buffer, 20, 1);
// 上面代码将一个24字节长度的ArrayBuffer对象,分成三个部分:
// 字节0到字节3:1个32位无符号整数
// 字节4到字节19:16个8位整数
// 字节20到字节23:1个32位浮点数
// 这种数据结构可以用如下的C语言描述:
// struct someStruct {
// unsigned long id;
// char username[16];
// float amountDue;
// }
</script>
</body>
</html>
04ArrayBuffer
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
//var buffer1 = new ArrayBuffer(32);//可视化数组的基础 直接在内存开辟缓存空间 32是字节
// 类型化数组是建立在ArrayBuffer对象的基础上的。它的作用是,分配一段可以存放数据的连续内存区域
//var buffer = new ArrayBuffer(32);
//buffer.byteLength //32
// 上面代码生成了一段32字节的内存区域。
// ArrayBuffer对象的byteLength属性,返回所分配的内存区域的字节长度。
//var buffer = new ArrayBuffer(8);
//var newBuffer = buffer.slice(0, 3);
// 上面代码拷贝buffer对象的前3个字节,生成一个新的ArrayBuffer对象。slice方法其实包含两步,第一步是先分配一段新内存,第二步是将原来那个ArrayBuffer对象拷贝过去。
// slice方法接受两个参数,第一个参数表示拷贝开始的字节序号,第二个参数表示拷贝截止的字节序号。如果省略第二个参数,则默认到原ArrayBuffer对象的结尾。
// 除了slice方法,ArrayBuffer对象不提供任何直接 {{读写内存}} 的方法,只允许在其上方建立视图,然后通过视图读写。
// var buffer = new ArrayBuffer(12);//开辟缓存
// console.log(buffer)
// var x = new Int32Array(buffer);//转化32 可视化数组
// console.log(x)
// x[1] = 1234;//进行赋值操作
// var slice = buffer.slice(4);//分割缓存空间 第4位 都是buffer内存
// console.log(slice)
// var y = new Int32Array(slice);//转化新的32 可视化数组
// console.log(x[1]);
// console.log(y[0]);
// x[1] = 6789;//修改数组中的值
// console.log(x[1]);
// console.log(y[0]);
// ArrayBuffer转为字符串,参数为ArrayBuffer对象
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
// 字符串转为ArrayBuffer对象,参数为字符串
function str2ab(str) {
console.log(str.length * 2)
var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
console.log(buf)
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
var buf = str2ab('你好')
console.log(buf)
var ab2str = ab2str(buf);
console.log(ab2str)
</script>
</body>
</html>
05Blobupdown
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
var input = document.getElementById("file"); // input file
input.onchange = function () {
var file = this.files[0];
if (!!file) {
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function () {
var binary = this.result;
upload(binary);
}
}
}
//文件上传
function upload(binary) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://xxxx/opload");
xhr.overrideMimeType("application/octet-stream");
//直接发送二进制数据
if (xhr.sendAsBinary) {
xhr.sendAsBinary(binary);
} else {
xhr.send(binary);
}
// 监听变化
xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 响应成功
}
}
}
}
</script>
</body>
</html>