likes
comments
collection
share

《图解 + 实战》File、Blob、TypeArray、DataView

作者站长头像
站长
· 阅读数 40

前言

最近一段时间做过很多关于文件及音视频相关的工作,故此根据个人实践结合资料查询学习,总结了关于文件、二进制相关的内容和大家分享交流,如果文章有不对的地方,恳请指正,✅通过本文,你将了解或者加深对以下概念的认知以及其应用场景:

  • File
  • Blob
  • ArrayBuffer
  • TypeArray
  • DataView
  • Buffer
  • FileReader
  • URL.createObjectURL

以及如何实现 ?

  1. 如何预览图片?
  2. 如何截取视频首帧(如果不借助第三方oss能力呢)?

1. Blob

Blob是对大数据块的不透明引用或者句柄。名字源于SQL数据库,表示“二进制大数据”(Binary Large Object)。在JavaScript中Blob通常表示二进制数据,但是不一定是大量数据。Blob是不透明的,我们可以对它执行的操作只有获取它的大小,MIME类型和将他切割成更小的Blob。——《JavaScript权威指南》

1.1 主要用法

1.1.1 构造函数使用

第一个参数是一个包含实际数据的数组(二进制数组也行),第二个参数是数据的类型(MIME type

《图解 + 实战》File、Blob、TypeArray、DataView

1.1.2 现有实例使用

其构造器Blob原型有size和type属性分别表示blob包含数据的大小和数据类型,其原型上方法有text(返回promise)和slice, 其中slice(start, end),返回start和end为切割blob的开始和结束字节点,返回值为blob

《图解 + 实战》File、Blob、TypeArray、DataView

1.2 应用场景

  1. 大文件上传(阿里云)时,会对file继承的blob的slice属性,对文件进行切割分片上传
  2. 可以通过blob结合FileReader来把其换成其他需要的数据比如Arraybuffer
  3. 可以暂存arrayBuffer数据,并通过URL.createObjectUrl(blob)通过同步的方式将其转成url以提供引用

2. File

File继承Blob,并基于用户的操作系统拓展了blob,使用户可以通过浏览器安全的访问系统的

《图解 + 实战》File、Blob、TypeArray、DataView

3. 获取File

3.1 从操作系统获取

3.1.1 input元素返回的filelist

《图解 + 实战》File、Blob、TypeArray、DataView

3.1.2 拖放操作获取File

《图解 + 实战》File、Blob、TypeArray、DataView

3.2 从网络中获取

从网络中获取文件(资源图片、视频),常用方式有两种

  1. 资源是存在cdn上面,通过url去访问获取资源
  2. 通过推流的方式获取资源(图片)
方式特点应用场景
cdn不经常变动的资源前端的脚本、用户信息头像、商品图、素材库图等存储资源
二进制流经常变动、实时生成二维码(小程序体验版),ai画像等

获取的二进制流可以通过blob转成url或者通过bota编码转成base64(见下文)

4. 操作文件

4.1 上传大文件对文件(file/blob)进行分割

《图解 + 实战》File、Blob、TypeArray、DataView 4.2 图片裁切🔧中将blob同步转为base64(dataul)

《图解 + 实战》File、Blob、TypeArray、DataView 当然也可以通过FileReader异步的读取blob/file来获取base64

《图解 + 实战》File、Blob、TypeArray、DataView 4.3 Base64 转为 blob

《图解 + 实战》File、Blob、TypeArray、DataView 4.4 处理音视频首帧

《图解 + 实战》File、Blob、TypeArray、DataView 上述流程简单说明:

  1. 通过拖拽或者选择的方式选取我们要上传的视频 file
  2. 为了获取视频首帧)通过createObjectUrl(file)获取到视频url
  3. 通过videoElement引用url,并插入dom
  4. 通过loadeddata事件回调🪝,canvas创建画布,通过toDataURL获取到视频首帧截图
  5. 然后再将其转成blob(4.3 Base64 转为 blob
  6. 调用oss方法上传首帧文件

5. ArrayBuffer/ DataView / TypeArray

为什么要使用它

  1. 原生的Array内部为了实现灵活性,牺牲了一部分性能,采用了哈希表的数据结构(详情
  2. buffer通过分配连续的内存,访问较原生array哈希方式遍历链表索引 更加高效

5.1 实例

canvas 《图解 + 实战》File、Blob、TypeArray、DataView typeArray 《图解 + 实战》File、Blob、TypeArray、DataView

Array vs Buffer

《图解 + 实战》File、Blob、TypeArray、DataView

名称特点应用场景
Array不限制类型、可能是稀疏的、不定长度大部分场景及json
ArrayBuffer实际存储数据的地方(内存)XHR、File API、Canvas等等各种地方,读取了一大串字节流
TypedArray单个长度和类型固定、字节对齐音视频、canvas、录音,处理网络中接收到的二进制数据,webwork中的大量数据处理
DataView每个元素长度和类型不固定,更灵活,性能相对较差构建二进制文件或格式话文件

5.2 ArrayBuffer

《图解 + 实战》File、Blob、TypeArray、DataView

以上述代码为例子:

  • line1: 申请了一个大小为8byte的内存大小区域,其地址是arrBuff
  • line2、line3: 在arrBuff对象上添加0a属性,并且为其赋值

注意:ArrayBuffer创建后,不能通过其引用直接操作(读写)它的元素,给其赋值,其实是在给其添加静态属性值,下面我们会证明为什么

这里后端拿到的response.data是arraybuffer并不能直接操作,而是通过typeArray进行操作的

5.3 TypeArray

注意!全局并没有TypeArray,其是作为Int8ArrayUint16Array等子类的统称,只是这些之类的原型,,所以只能通过 Object.getPrototypeOf(Int8Array) 及类似方式访问

5.3.1 举个🌰子

《图解 + 实战》File、Blob、TypeArray、DataView 图片标记点按照数字依次为:

  1. 二进制类型数组中的元素,默认填充0
  2. 类型数组实际引用的buffer,只读
  3. 每个字节的地址
  4. 不同类型type array
  5. 进制类型:dec(Decimal System) 十进制,hex 十六进制, oct 八进制
  6. 不同进制下对应的buffer存的数值

5.3.2 无符号类二进制数组

其形式为Uint+8^n+Array,这里拿Uint8Array举例: 对于无符号8比特(1byte)的类型的

《图解 + 实战》File、Blob、TypeArray、DataView 由上图得出Uint8Array有以下几点特点:

  1. 单个元素的可存值范围 [0, 256)
  2. 正向溢出,一直减去256,直至得到的值在[0, 256)区间的数字,作为其最终值
  3. 负向溢出,一直256,直至得到的值在[0, 256)区间的数字,作为其最终值
  4. 溢出的值,不会加到下一个元素

5.3.3 有符号类二进制数组

上述代码稍作改动,有符号8比特(1byte)的Int8Array类型的

《图解 + 实战》File、Blob、TypeArray、DataView

由上图得出Int8Array有以下几点特点:

  1. 单个元素的可存值范围 [-128, 127)
  2. 正向溢出,一直减去256,直至得到的值在[-128, 127)区间的数字,作为其最终值
  3. 负向溢出,一直256,直至得到的值在[-128, 127)区间的数字,作为其最终值
  4. 溢出的值,不会加到下一个元素

5.3.4 主要用法及应用场景

  1. 使用arrayBuffer实例作为参数,提供操作arrayBuffer方法
  2. 创建一个特定类型的typearray
new TypedArray()
new TypedArray(length)
new TypedArray(typedArray)
new TypedArray(object)

new TypedArray(buffer)
new TypedArray(buffer, byteOffset)
new TypedArray(buffer, byteOffset, length)

同一类型,如Int8ArrayUint8Array分为有符号和无符号,取值范围不同,其中取值范围表示,每个类数组(集合)的单个元素的取值范围

《图解 + 实战》File、Blob、TypeArray、DataView 关于typeArray属性:

  1. length:上述代码构造函数中的3、6表示创建类型化数组长度(length)是3、6,即包含3、6个元素,用0填充
  2. bytelength, 数组的长度大小(字节),其为 BYTES_PER_ELEMENT * length
  3. BYTES_PER_ELEMENT: 类型化数组的每个元素的空间大小(字节)

注意在构建typeArray实例时

  1. 要注意传入的arrayBuffer的字节大小要和类型数组元素对齐,即buffer大小是自元素大小的整数倍,这样才能被类型元素平均分配
  2. 同理,偏移量offeset(字节),也要是BYTES_PER_ELEMENT倍数

关于字节对齐: 下面是vue-cropper图片菜切开源项目,当传入到Uint16Array的字节大小不为2的整数倍时就会报错如图所示错误,所以需要对传入buffer的len做偶数适配 《图解 + 实战》File、Blob、TypeArray、DataView

《图解 + 实战》File、Blob、TypeArray、DataView

5.4 DataView

DataView 视图是一个可以从二进制 ArrayBuffer 对象中读写多种数值类型的底层接口 --- Mdn

《图解 + 实战》File、Blob、TypeArray、DataView

其中关于setInt8^n和对应的getInt8^,拿 view.setInt16(7, 120)view.getInt16(7) 举例🌰, 调用过程是这样的:

  1. 通过var buff10 = new ArrayBuffer(10)偷到了ArrayBuffer老巢的地址,于是上门去找ArrayBuffer
  2. 到了之后,从前面偏移(空出来)7个字节开始,隔出来一个2byte的内存空间专门来存放有符号数据 120
  3. view.getInt16(7)从前面偏移(空出来)7个字节开始,获取一个2byte的内存空间专门内存的值

上述代码,内存操作示意图:

《图解 + 实战》File、Blob、TypeArray、DataView

通过上述代码,我们可知:

  1. TypeArray和DataView都可以操作ArrayBuffer,但是前者更加灵活,每个元素长度和类型都可以不一致
  2. DataView 不会有对齐问题

##6. 总结

使用类型化数组的关键是性能和内存。它们最常用于特殊场景,但是当您只需要存储数值(或 utf-8 字符串、加密向量等)时,在普通情况下使用它们并没有什么问题。它们速度快且内存占用少

《图解 + 实战》File、Blob、TypeArray、DataView

参考

转载自:https://juejin.cn/post/7284513473316667453
评论
请登录