JavaScript 困惑之 ArrayBuffer
在就版本的 JavaScrip中, 是没有读写二进制数据能力的,但随着 es5 中 Blob 对象的引入以及 es6 中 ArrayBuffer 对象、TypedArray 和 DataView 对象的规范化, JS 处理二进制数据的能力大幅度增强,也能直接处理文件流,网络流等二进制 Buffer 数据了。
1、Blob对象
Blob(Binary Large Object)表示二进制类型的大对象。在数据库管理系统中,将二进制数据存储为一个单一个体的集合。Blob 通常是影像、声音或多媒体文件。在 JavaScript 中 Blob 类型的对象表示不可变的类似文件对象的原始数据。 为了更直观的感受 Blob 对象,我们先来使用 Blob 构造函数,创建一个 aBlob 对象:
var aBlob = new Blob(blobParts, options);
- blobParts:它是一个由 ArrayBuffer,ArrayBufferView,Blob,DOMString 等对象构成的数组。DOMStrings 会被编码为 UTF-8。
- options:一个可选的对象,包含以下两个属性:
type —— 默认值为 ""
,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。
endings —— 默认值为 "transparent"
,用于指定包含行结束符 \n
的字符串如何被写入。它是以下两个值中的一个:"native"
,代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 "transparent"
,代表会保持 blob 中保存的结束符不变。
blob对象的主要属性方法:
属性:
- size(只读):表示
Blob
对象中所包含数据的大小(以字节为单位)。 - type(只读):一个字符串,表明该
Blob
对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。
方法:
- slice([start[, end[, contentType]]]):返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。
- stream():返回一个能读取 blob 内容的
ReadableStream
。 - text():返回一个 Promise 对象且包含 blob 所有内容的 UTF-8 格式的
USVString
。 - arrayBuffer():返回一个 Promise 对象且包含 blob 所有内容的二进制格式的
ArrayBuffer
。
Blob
对象是不可改变的。我们不能直接在一个 Blob 中更改数据,但是我们可以对一个 Blob 进行分割,从其中创建新的 Blob 对象,将它们混合到一个新的 Blob 中。这种行为类似于 JavaScript 字符串:我们无法更改字符串中的字符,但可以创建新的更正后的字符串。
2、File对象
File 对象代表一个文件,用来读写文件信息。它继承了 Blob 对象,或者说是一种特殊的 Blob 对象,所有可以使用 Blob 对象的场合都可以使用它。
我们接触的多数关于 File 的操作都是读取,js也为我们提供了手动创建 File 对象的构造函数:File(bits, name[, options])。
var myFile = new File([], 'file.bin', { lastModified: new Date(2018, 1, 1), }); myFile.lastModified // 1517414400000 myFile.name // "file.bin" myFile.size // 0 myFile.type //
- bits (required) ArrayBuffer,ArrayBufferView,Blob,或者 Array[string] —或者任何这些对象的组合。这是 UTF-8 编码的文件内容。。
- name [String] (required) 文件名称,或者文件路径.
- options [Object] (optional) 选项对象,包含文件的可选属性。可用的选项如下:
- type: string, 表示将要放到文件中的内容的MIME类型。默认值为 ‘’ 。
- lastModified: 数值,表示文件最后修改时间的 Unix 时间戳(毫秒)。默认值为 Date.now()。
3、FileList 对象
FileList对象是一个类似数组的对象,代表一组选中的文件,每个成员都是一个 File 实例。它主要出现在两个场合。文件控件节点()的files属性,返回一个 FileList 实例。
拖拉一组文件时,目标区的DataTransfer.files属性,返回一个 FileList 实例。
var files = document.getElementById('fileItem').files; files instanceof FileList // true
3、FileReader 对象
FileReader 有以下的实例属性。
- FileReader.error:读取文件时产生的错误对象
- FileReader.readyState:整数,表示读取文件时的当前状态。一共有三种可能的状态,0表示尚未加载任何数据,1表示数据正在加载,2表示加载完成。
- FileReader.result:读取完成后的文件内容,有可能是字符串,也可能是一个 ArrayBuffer 实例。
- FileReader.onabort:abort事件(用户终止读取操作)的监听函数。
- FileReader.onerror:error事件(读取错误)的监听函数。
- FileReader.onload:load事件(读取操作完成)的监听函数,通常在这个函数里面使用result属性,拿到文件内容。
- FileReader.onloadstart:loadstart事件(读取操作开始)的监听函数。
- FileReader.onloadend:loadend事件(读取操作结束)的监听函数。
- FileReader.onprogress:progress事件(读取操作进行中)的监听函数。
其主要方法如下
- abort():void 终止文件读取操作
- readAsArrayBuffer(file):void 异步按字节读取文件内容,结果用ArrayBuffer对象表示
- readAsBinaryString(file):void 异步按字节读取文件内容,结果为文件的二进制串
- readAsDataURL(file):void 异步读取文件内容,结果用data:url的字符串形式表示
- readAsText(file,encoding):void 异步按字符读取文件内容,结果用字符串形式表示
其中readAsArrayBuffer可以将文件转换为arraybuffer\text\data等
function onChange(event) { var file = event.target.files[0]; var reader = new FileReader(); reader.onload = function (event) { console.log(event.target.result) }; reader.readAsText(file); }
4、ArrayBuffer对象
代表内存之中的一段二进制数据,可以用数组的方法操作内存,ArrayBuffer 是视图或TypeArray的底层缓冲区,不能直接操作ArrayBuffer,需要通过视图或TypeArray来操作它
ArrayBuffer()是一个普通的JavaScript构造函数,可用于在内存中分配特定数量的字节空间。
const buf = new ArrayBuffer(16); // 在内存中分配16 字节 alert(buf.byteLength);
5、TypedArray视图对象
我们无法对ArrayBuffer 进行直接操作,需要通过TypedArray进行操作
共包括 9 种类型的视图,比如Uint8Array
(无符号 8 位整数)数组视图, Int16Array
(16 位整数)数组视图, Float32Array
(32 位浮点数)数组视图等等。
- Int8Array:8位有符号整数,长度1个字节。
- Uint8Array:8位无符号整数,长度1个字节。
- Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。
- Int16Array:16位有符号整数,长度2个字。
- Uint16Array:16位无符号整数,长度2个字节。
- Int32Array:32位有符号整数,长度4个字节。
- Uint32Array:32位无符号整数,长度4个字节。
- Float32Array:32位浮点数,长度4个字节。
- Float64Array:64位浮点数,长度8个字节。
let buf = new ArrayBuffer(32) let int32 = new Int32Array(buf) let uint8 = new Uint8Array(buf) console.log(int32[0]) // 0 console.log(uint8[0]) // 0
// 还可以直接修改
int32[0] = 1 console.log(int32[0]) // 1 console.log(uint8[0]) // 1
6、DataView 对象:
TypedArray只能放置一种数据类型,对于要存放不同的 数据类型,则需要DataView,不同于类型化数组,一个数组只能存放同一类型的数据,DataView 可以在内存中存放不同类型的数据。