进制(二):Blob、File、ArrayBuffer、DataView、TypedArray

js 的进制转换第二篇,Blob、File、ArrayBuffer、DataView、TypedArray。

上回说到,[js 中各个进制是怎么转换的](/home/进制(一) js的各种进制转换/),接下来看看,二进制在 js 中的实际使用和如何操作。

背景

实际开发的过程中,调用后端接口下载文件一般有两种方式 (以 axios 为例):

  • 一是后端存储文件,生成文件地址,前端拿到地址后打开,如

    1
    2
    3
    4
    5
    6
    7
    // 返回的 url 为文件地址 http://xxx.xxx.xlsx
    axios.post(`${BASE_URL}/api`).then((res) => {
    // open
    window.open(res.url)
    // location.href
    location.href = res.url
    })
  • 二是以二进制流的形式返回,此时响应头设置的 content-type 为 application/octet-stream:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    const downloadFile = (file, fileName = 'filename.xlsx') => {
    // 如果 response type 为 blob
    let blob = file
    // 如果 response type 为 arraybuffer,转换为 Blob
    if (file instanceof ArrayBuffer) {
    blob = new Blob([file])
    }
    // 创建URL对象
    const url = URL.createObjectURL(blob)
    const el = document.createElement('a')
    el.href = url
    el.download = fileName
    el.click()
    // 释放URL对象
    URL.revokeObjectURL(url)
    }
    // 返回二进制流
    axios
    .post(`${BASE_URL}/api`, {
    responseType: 'blob', // 或者 arraybuffer
    })
    .then((res) => {
    downloadFile(res)
    })

这两种方式是很常用的

那什么是 Blob 和 ArrayBuffer 呢,与很少见到的 DataView、TypedArray,或者 常见的 File 有什么关系呢

解释

理了一下之间的关系,大致如下。

  • Blob、File、ArrayBuffer 可以归为一类,它们都是数据或者说缓冲区;
  • FileReader 算是一种工具,用来读取数据;
  • DataView、TypedArray 是一种视图,视图对象本身并不存储任何东西。它是一副“眼镜”,透过它来解释存储在 ArrayBuffer 中的字节。

Blob

Blob (binary large object,二进制大文件对象)。表示一个不可变、原始数据的类文件对象。
只可以 slice 拆分,不能进行细粒度的操作,细粒度的操作需要转换成 ArrayBuffer。

创建:

1
2
3
let blobObj = new Blob(array, options)
// array:一堆数据构成的数组
//options:设置一些属性,主要是type属性

属性:

1
2
size:数据的字节大小(只读)
type:数据的MIME类型,例如'image/png'(只读)

操作方法:

1
2
3
//start:分割起始点
//end: 分割终点
Blob.slice(start, end)

File

File 就是文件,继承自 Blob,也是二进制对象。(可以用在任意的 Blob 类型的 context 中。比如说,FileReader 就能处理 Blob 和 File)。
有自己特有的属性和方法, 可以看到。

创建,类似于 Blob:

1
2
3
4
// array:一堆数据构成的数组
// name: 文件名
// options:设置一些属性,type属性、lastModified
let file = new File(array, name, options)

常见属性:

1
2
3
4
5
name:文件名
size:文件大小
lastModified :最后修改时间(时间戳)
lastModifiedDate: 最后修改时间Data对象
type:MIME类型

File 继承于 Blob,所以也拥有 slice 方法。

1
new File([1], 'a.js').slice()

ArrayBuffer

ArrayBuffer 是内存上一段二进制数据,我们可以借助工具 TypeArray、DataView 对它进行读写。

创建:

1
2
let buffer = new ArrayBuffer(16) // 创建一个长度为 16 字节的 buffer
console.log(buffer.byteLength) // 16

区别:

  • ArrayBuffer 是底层二进制数据,可以视图 TypeArray、DataView 进行读写。
  • 而 Blob 是对底层二进制数据的封装,js 获取到的是一个整体,能够读取他的大小,类型,但是不能看到细节。
  • Blob 作为一个整体文件,更适合用于传输;而只有需要关注细节(比如要修改某一段数据时),才需要用到 ArrayBuffer。

ArrayBuffer 转 Blob

1
2
3
4
// 使用 new Blob 即可把 ArrayBuffer 的二进制数据进行封装
const arraybuffer = new ArrayBuffer(16)
const blob = new Blob([arraybuffer])
// Blob {size: 16, type: ''}

Blob 转 ArrayBuffer

1
2
3
// ArrayBuffer() 可以将 blob 转换成 ArrayBuffer
const blob = new Blob([1])
const arraybuffer = await blob.ArrayBuffer()

FileReader

FileReader
通过 fileReader 可以将 Blob、File 读取为不同的格式,常见:

  1. 将图片文件转换为 base64
1
2
3
4
5
6
7
8
9
10
11
12
// FileReader.readAsDataURL(blob 将二进制数据读取并编码为 Base64 格式
var file = document.querySelector('input[type=file]').files[0]
var reader = new FileReader()

reader.onload = (e) => {
// base64
console.log(e.result)
}
// 转换成 base64
reader.readAsDataURL(file)
// 也可以转换为 arraybuffer -----------------
reader.readAsArrayBuffer(file)

TypedArray

TypedArray 没有直接的构造函数,常见的对他的实现有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 下面代码是语法格式,不能直接运行,
// TypedArray 关键字需要替换为底部列出的构造函数。
new TypedArray(); // ES2017中新增
new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object);
new TypedArray(buffer [, byteOffset [, length]]);

// TypedArray 指的是以下的其中之一:
Int8Array();
Uint8Array();
Uint8ClampedArray();
Int16Array();
Uint16Array();
Int32Array();
Uint32Array();
Float32Array();
Float64Array();

Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(00000000 ~ 11111111),称为 “8 位无符号整数”。
Uint16Array —— 将每 2 个字节视为一个 0 到 65535 之间的整数,称为 “16 位无符号整数”。
Uint32Array —— 将每 4 个字节视为一个 0 到 4294967295 之间的整数,称为 “32 位无符号整数”。
Float64Array —— 将每 8 个字节视为一个 5.0x10-324 到 1.8x10308 之间的浮点数。

因此,一个 16 字节 ArrayBuffer 中的二进制数据可以解释为:

  • 16 个“小数字”
  • 8 个更大的数字(每个数字 2 个字节)
  • 4 个更大的数字(每个数字 4 个字节)
  • 2 个高精度的浮点数(每个数字 8 个字节)。

实例:

1
2
3
let arr = new Uint8Array([0, 1, 2, 3])
alert(arr.length) // 4,创建了相同长度的二进制数组
alert(arr[1]) // 1,用给定值填充了 4 个字节(无符号 8 位整数)

TypedArray 具有常规的 Array 方法,可以遍历(iterate),map,slice,find 和 reduce 等。
但没有 splice —— 无法“删除”一个值,因为类型化数组是缓冲区(buffer)上的视图,并且缓冲区(buffer)是固定的、连续的内存区域。我们所能做的就是分配一个零值。
也没有 concat 方法。

以上

下一篇:运用 进制(四):利用二进制解码 wbmp 并转换为 png 图片