梳理前端二进制相关概念
虽然前端平时很少直接操作二进制,但是在一些场景下,比如canvas处理图片、fetch请求、文件上传、图片压缩等情况下,我们会用到与二进制相关的一些方法,因此还是有必要梳理梳理下述几个
Javascript
操作二进制的接口,了解一些文件图像相关知识
首先我们大概介绍一下这几个概念,后面再进行对比
二进制数组(类型化数组)
- 以数组的语法处理二进制数据,所以统称为二进制数组
- 类似C语言中的数组,可以通过下标直接操作字节
- 最初设计的目的与
WebGL
项目有关,为了提升JS与显卡之间大量、实时的数据交换的性能(直接操作二进制)
二进制数组可分为以下三类对象
ArrayBuffer
对象
表示内存之中的一段原始二进制数据
语法
但现在我们还不能直接对它进行操作,因此要引进后面俩概念
我们可以通过构造函数来申请一段
ArrayBuffer
区域const buf = new ArrayBuffer(32); //构造函数的参数为所需内存的字节大小
每个字节默认值为0
不能直接操作,就比如C里面
malloc
一片内存出来也需要转化成指针来使用
Js可以通过下面的两种视图对象(TypedArray
, DataView
)来对ArrayBuffer
进行操作:将缓冲区中的数据表示为特定的格式,然后通过这些特定的格式来读写缓冲区内容
TypedArray
视图
包括9种类型的视图
- 这些都和C语言中的概念相同,这里就不作解释了
-
数据类型 字节长度 含义 对应的 C 语言类型 Int8 1 8 位带符号整数 signed char Uint8 1 8 位不带符号整数 unsigned char Uint8C 1 8 位不带符号整数(自动过滤溢出) unsigned char Int16 2 16 位带符号整数 short Uint16 2 16 位不带符号整数 unsigned short Int32 4 32 位带符号整数 int Uint32 4 32 位不带符号的整数 unsigned int Float32 4 32 位浮点数 float Float64 8 64 位浮点数 double
可以读写类型较为简单的二进制数据
其实没有叫
TypedArray
这名字的构造函数,它只是对这九种构造函数的合称:Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array
例如我们来讲这个名字特殊一点的
Uint8ClampedArray
- 8位无符号整型固定数组,也即它的值固定在[0-255]之间(若指定为区间外的值将会被替换为0或255)
语法
// 创建一个8字节的ArrayBuffer
const b = new ArrayBuffer(8);
// 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
const v1 = new Int32Array(b);
// 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
const v2 = new Uint8Array(b, 2);
// 创建一个指向b的Int16视图,开始于字节2,长度为2
const v3 = new Int16Array(b, 2, 2);方法和数组类似,但是注意它没有
concat
方法
DataView
视图
相比于前者,
DataView
是可以自定义格式的视图,因此它可以用来读写类型更复杂的二进制数据提供更多的操作选项,支持设定字节序(大端或者小端)
语法
new DataView(ArrayBuffer buffer [, 字节起始位置 [, 长度]]);
//栗子
const buffer = new ArrayBuffer(24);
const dv = new DataView(buffer);- 类似,把
get
改成set
就行 - 必须要输入一个字节序号,表示从哪个字节开始读取
读取内存
const buffer = new ArrayBuffer(24);
const dv = new DataView(buffer);
// 从第1个字节读取一个8位无符号整数
const v1 = dv.getUint8(0);
// 从第2个字节读取一个16位无符号整数
const v2 = dv.getUint16(1);
// 从第4个字节读取一个16位无符号整数
const v3 = dv.getUint16(3);写入内存
- 创建视图
- 类似,把
总结一下上面三个,
ArrayBuffer
就是内存中一段原始的01串,而为了操作它,我们可以使用TypedArray
或DataView
,把这段01串分开一段段装到特定格式的小盒子里面(视图),然后对盒子里的数据进行操作,这里盒子之间也是可以重合的,也被称为复合视图
接下来我们来讲将另一个API
Blob
Binary Large Object ,表示不可变的原始二进制数据
类比string
首先,我们使用构造函数new一个Blob来看看
两个只读属性,分别是size: 数据大小和type: MIME类型(例如:.html对应 text/html;.png 对应 image/png; .txt 对应 text/plain)、
Blob由一个可选的字符串(type)和blobParts组成
语法
const blob = new Blob(blobParts[, options])
- 其中的
blobParts
表示一个数组,元素为ArrayBuffer
,ArrayBufferView
,Blob
,DOMString
等对象 options
是一个可选的对象,包含两个属性:创建
Blob
这里要注意的是:
Blob
对象是不可改变的,但是可以进行分割,并创建出新的Blob
对象,将它们混合到一个新的Blob
中。类似于 JavaScript 字符串:我们无法更改字符串中的字符,但可以创建新的字符串
type
(默认值为""),表示MIME
类型endings
(默认值为“transparent"
),用于指定行结束符\n
如何处理
File
File对象
- 继承自Blob,将其扩展使得它能够支持用户系统上的文件
- 多了一个lastModified属性表示修改时间
- 同样可以使用构造函数
FileList
包含
File
文件集合的list,通常来自的
files
属性比如我们可以在指定
multiple
来多选文件,然后通过数组下标来获取对应的File对象<input type="file" id="myfileinput" multiple>
const fileInput = document.getElementById("myfileinput")
// files 是一个 FileList 对象(类似于NodeList对象)
const files = fileInput.files
for (var i = 0; i file = files[i] //或者这样写:file = files.item(i);
console.log(file.name)
}使用
files
,就要用到接下来要将的FileReader
了
FileReader
readAsArrayBuffer
readAsText
readAsDataURL
- 补充,
base64
编码相关 - 基于 64 个可打印字符来表示二进制数据
- 每6个比特为一个单元,对应一个字符(2的6次方)
- 可以用
btoa()
,atob()
函数进行转换(ASCII和Blob) - 用来读取
File
和Blob
对象的内容 - 异步读取,可以在
onload
的result
属性中拿到结果 - 常用的
readAsDataURL
方法拿到的是base64
编码的字符串 - 除此之外,还有
- 因此,我们可以很方便地使用
FileReader
来进行我们需要的转化,例如后文要提到的将ArrayBuffer
转化为Blob
比较&转化
ArrayBuffer
&Blob
表示不可变的类似文件对象的原始数据,(影像、声音或多媒体文件)
- 可以位于磁盘、高速缓存内存和其他不可用的位置
- 还有重要的一点:
Blob
是不可变的 - 在需要写入的时候,我们通常会使用
ArrayBuffer
,其它情况用的更多的是Blob
表示通用的,固定长度的原始二进制数据缓冲区(是存在内存中的) * 可以通过视图进行操作
ArrayBuffer
在使用时也更接近真实的二进制,更底层ArrayBuffer
Blob
二者可以相互转化
ArrayBuffer
转Blob
const blob = new Blob([1,2,3,4,5]);
const reader = new FileReader(); //借助FileReader对象
reader.onload = function() {
console.log(this.result);
}
reader.readAsArrayBuffer(blob); //这里将blob转化成了ArrayBuffer类型Blob
转ArrayBuffer
const buffer = new ArrayBuffer(8)
const blob = new Blob([buffer]) //这里通过构造函数产生一个blob对象
DataURL
&ObjectURL
- 其中
mediatype
是表示MIME
类型的字符串,默认值为"text/plain;charset=US-ASCII"
BlobURL
的格式是blob:域名/uuid
DataURL
的格式是data:[[;base64],
- 前者长度往往更短,因为后者的数据中存储着图片的
base64
编码 - 我们可以直接将
DataURL
复制到浏览器地址栏进行访问,但BlobURL
则不能
- 其中
既然讲了这些概念,就拿图像做例子,看看有哪些表示类型
image相关
下面是图像表示的五种数据类型
DOM
- 例如
Data URL
、Object URL
(上文有对它们进行比较)
这个标签我们再熟悉不过了URL
- 例如
canvas
中有很多图片操作的接口是我们经常用到的,例如drawImage
方法...文件类型
Blob
File
ImageData
width
height
data
data
中会保存图像元素对应的RGBA
信息- 这里的
ImageData
是一个Js对象,含有下列属性
Buffer
- 它是
Node.js
中一种特殊的Uint8Array
- 该类是
Node.js
用来创建一个专门存放二进制数据的缓冲区 - 这部分还有很多知识点,详细的可以看看官方文档 https://nodejs.org/api/buffer.html
- 它是
希望以上二进制相关整理能给学习前端的小伙伴们带来帮助
参考链接:
https://es6.ruanyifeng.com/#docs/arraybuffer
https://vivaxyblog.github.io/2019/11/08/comprehensive-image-processing-on-browsers-cn.html
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/FileReader