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://jinso.top/article/modern-javascript-others-binary
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。













