type
status
date
slug
summary
tags
category
icon
password
Edited
Sep 15, 2022 01:17 PM
Created
Sep 13, 2022 07:45 AM
二进制 数据 & 文件
基本的二进制对象是
ArrayBuffer
—— 对固定长度的连续内存空间的引用。ArrayBuffer
是一个内存区域。它里面存储了什么?无从判断。只是一个原始的字节序列。如要操作
ArrayBuffer
,我们需要使用“视图”对象。视图对象本身并不存储任何东西。它是一副“眼镜”,透过它来解释存储在
ArrayBuffer
中的字节。例如:
Uint8Array
—— 将ArrayBuffer
中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位,因此只能容纳那么多)。这称为 “8 位无符号整数”。
Uint16Array
—— 将每 2 个字节视为一个 0 到 65535 之间的整数。这称为 “16 位无符号整数”。
Uint32Array
—— 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”。
Float64Array
—— 将每 8 个字节视为一个5.0x10324
到1.8x10308
之间的浮点数。
ArrayBuffer
是核心对象,是所有的基础,是原始的二进制数据。
但是,如果我们要写入值或遍历它,基本上几乎所有操作 —— 我们必须使用视图(view)
TypedArray
所有这些视图(
Uint8Array
,Uint32Array
等)的通用术语是 TypedArray。它们共享同一方法和属性集。请注意,没有名为
TypedArray
的构造器,它只是表示 ArrayBuffer
上的视图之一的通用总称术语参数有 5 种变体:
Uint8Array
,Uint16Array
,Uint32Array
—— 用于 8、16 和 32 位的整数。Uint8ClampedArray
—— 用于 8 位整数,在赋值时便“固定“其值(见下文)。
Int8Array
,Int16Array
,Int32Array
—— 用于有符号整数(可以为负数)。
Float32Array
,Float64Array
—— 用于 32 位和 64 位的有符号浮点数。
TypedArray 方法
TypedArray
具有常规的 Array
方法,但有个明显的例外。我们可以遍历(iterate),
map
,slice
,find
和 reduce
等。但有几件事我们做不了:
- 没有
splice
—— 我们无法“删除”一个值,因为类型化数组是缓冲区(buffer)上的视图,并且缓冲区(buffer)是固定的、连续的内存区域。我们所能做的就是分配一个零值。
- 无
concat
方法。
还有两种其他方法:
arr.set(fromArr, [offset])
从offset
(默认为 0)开始,将fromArr
中的所有元素复制到arr
。
arr.subarray([begin, end])
创建一个从begin
到end
(不包括)相同类型的新视图。这类似于slice
方法(同样也支持),但不复制任何内容 —— 只是创建一个新视图,以对给定片段的数据进行操作。
DataView
DataView 是在
ArrayBuffer
上的一种特殊的超灵活“未类型化”视图。它允许以任何格式访问任何偏移量(offset)的数据。- 对于类型化的数组,构造器决定了其格式。整个数组应该是统一的。第 i 个数字是
arr[i]
。
- 通过
DataView
,我们可以使用.getUint8(i)
或.getUint16(i)
之类的方法访问数据。我们在调用方法时选择格式,而不是在构造的时候。
buffer
—— 底层的ArrayBuffer
。与类型化数组不同,DataView
不会自行创建缓冲区(buffer)。我们需要事先准备好。
byteOffset
—— 视图的起始字节位置(默认为 0)。
byteLength
—— 视图的字节长度(默认至buffer
的末尾)。
两个术语,用于对二进制数据进行操作的方法的描述:
ArrayBufferView
是所有这些视图的总称。
BufferSource
是ArrayBuffer
或ArrayBufferView
的总称。
TextDecoder & TextEncoder
TextDecoder
TextDecoder
对象在给定缓冲区(buffer)和编码格式(encoding)的情况下,允许将值读取为实际的 JavaScript 字符串。label
—— 编码格式,默认为utf-8
,但同时也支持big5
,windows-1251
等许多其他编码格式。
options
—— 可选对象:fatal
—— 布尔值,如果为true
则为无效(不可解码)字符抛出异常,否则(默认)用字符\uFFFD
替换无效字符。ignoreBOM
—— 布尔值,如果为true
则 BOM(可选的字节顺序 Unicode 标记),很少需要使用。
input
—— 要被解码的BufferSource
。
options
—— 可选对象:stream
—— 对于解码流,为 true,则将传入的数据块(chunk)作为参数重复调用decoder
。在这种情况下,多字节的字符可能偶尔会在块与块之间被分割。这个选项告诉TextDecoder
记住“未完成”的字符,并在下一个数据块来的时候进行解码。
示例:
TextEncoder
TextEncoder
做相反的事情 —— 将字符串转换为字节。只支持
utf-8
编码。它有两种方法:
encode(str)
—— 从字符串返回Uint8Array
。
encodeInto(str, destination)
—— 将str
编码到destination
中,该目标必须为Uint8Array
。
Blob
Blob
由一个可选的字符串 type
(通常是 MIME 类型)和 blobParts
组成 —— 一系列其他 Blob
对象,字符串和 BufferSource
。blobParts
是Blob
/BufferSource
/String
类型的值的数组。
options
可选对象:type
——Blob
类型,通常是 MIME 类型,例如image/png
,endings
—— 是否转换换行符,使Blob
对应于当前操作系统的换行符(\r\n
或\n
)。默认为"transparent"
(啥也不做),不过也可以是"native"
(转换)。
用
slice
方法来提取 Blob
片段:byteStart
—— 起始字节,默认为 0。
byteEnd
—— 最后一个字节(专有,默认为最后)。
contentType
—— 新 blob 的type
,默认与源 blob 相同。
Blob
对象是不可改变的我们无法直接在
Blob
中更改数据,但我们可以通过 slice
获得 Blob
的多个部分,从这些部分创建新的 Blob
对象,将它们组成新的 Blob
,等。Blob 用作 URL
多亏了type
,让我们也可以下载/上传Blob
对象,而在网络请求中,type
自然地变成了Content-Type
。
Blob 可以很容易用作
<a>
、<img>
或其他标签的 URL,来显示它们的内容。URL.createObjectURL
取一个 Blob
,并为其创建一个唯一的 URL,形式为 blob:<origin>/<uuid>
。不过它有个副作用。虽然这里有
Blob
的映射,但 Blob
本身只保存在内存中的。浏览器无法释放它。因此,如果我们创建一个 URL,那么即使我们不再需要该
Blob
了,它也会被挂在内存中。URL.revokeObjectURL(url)
从内部映射中移除引用,因此允许 Blob
被删除(如果没有其他引用的话),并释放内存。Blob 转换为 base64
URL.createObjectURL
的一个替代方法是,将 Blob
转换为 base64-编码的字符串。这种编码将二进制数据表示为一个由 0 到 64 的 ASCII 码组成的字符串,非常安全且“可读“。更重要的是 —— 我们可以在 “data-url” 中使用此编码。
“data-url”
的形式为data:[<mediatype>][;base64],<data>
。我们可以在任何地方使用这种 url,和使用“常规” url 一样。
使用内建的
FileReader
对象来将 Blob
转换为 base64。它可以将 Blob
中的数据读取为多种格式。URL.createObjectURL(blob)
- 如果介意内存,我们需要撤销(revoke)它们
- 直接访问
Blob
,无需“编码/解码”
Blob 转换为 data url
- 无需撤销(revoke)任何操作。
- 对大的
Blob
进行编码时,性能和内存会有损耗。
Image 转换为 blob
图像操作是通过
<canvas>
元素来实现的:- 使用
canvas.drawImage
在 canvas 上绘制图像(或图像的一部分)。
- 调用 canvas 方法
.toBlob(callback, format, quality)
创建一个Blob
,并在创建完成后使用其运行callback
。
可以将callback换成async/await
Blob 转换为 ArrayBuffer
Blob 转换为 Stream
当我们读取和写入超过
2 GB
的 blob 时,将其转换为 arrayBuffer
的使用对我们来说会更加占用内存。这种情况下,我们可以直接将 blob 转换为 stream 进行处理。stream 是一种特殊的对象,我们可以从它那里逐部分地读取(或写入)。
Blob
接口里的 stream()
方法返回一个 ReadableStream
,在被读取时可以返回 Blob
中包含的数据。File 和 FileReader
File
File 对象继承自
Blob
,并扩展了与文件系统相关的功能。有两种方式可以获取它。
第一种,与
Blob
类似,有一个构造器:new File(fileParts, fileName, [options])
fileParts
—— Blob/BufferSource/String 类型值的数组。
fileName
—— 文件名字符串。
options
—— 可选对象:lastModified
—— 最后一次修改的时间戳(整数日期)。
第二种,更常见的是,我们从
<input type="file">
或拖放或其他浏览器接口来获取文件。在这种情况下,file 将从操作系统(OS)获得 this 信息。由于
File
是继承自 Blob
的,所以 File
对象具有相同的属性,附加:name
—— 文件名,
lastModified
—— 最后一次修改的时间戳。
FileReader
FileReader 是一个对象,其唯一目的是从
Blob
(因此也从 File
)对象中读取数据。它使用事件来传递数据,因为从磁盘读取数据可能比较费时间。
主要方法:
readAsArrayBuffer(blob)
—— 将数据读取为二进制格式的ArrayBuffer
。
readAsText(blob, [encoding])
—— 将数据读取为给定编码(默认为utf-8
编码)的文本字符串。
readAsDataURL(blob)
—— 读取二进制数据,并将其编码为 base64 的 data url。
abort()
—— 取消操作。
read*
方法的选择,取决于我们喜欢哪种格式,以及如何使用数据。readAsArrayBuffer
—— 用于二进制文件,执行低级别的二进制操作。对于诸如切片(slicing)之类的高级别的操作,File
是继承自Blob
的,所以我们可以直接调用它们,而无需读取。
readAsText
—— 用于文本文件,当我们想要获取字符串时。
readAsDataURL
—— 当我们想在src
中使用此数据,并将其用于img
或其他标签时。正如我们在 Blob 一章中所讲的,还有一种用于此的读取文件的替代方案:URL.createObjectURL(file)
。
读取过程中,有以下事件:
loadstart
—— 开始加载。
progress
—— 在读取过程中出现。
load
—— 读取完成,没有 error。
abort
—— 调用了abort()
。
error
—— 出现 error。
loadend
—— 读取完成,无论成功还是失败。
读取完成后,我们可以通过以下方式访问读取结果:
reader.result
是结果(如果成功)
reader.error
是 error(如果失败)。
使用最广泛的事件无疑是
load
和 error
。示例:
参考链接:
- 作者:JinSo
- 链接:https://jinso365.top/article/modern-javascript-others-binary
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。