二进制数据
1. Blob
Blob 全称为 binary large object ,即二进制大对象,它是 JavaScript 中的一个对象,表示原始的类似文件的数据。下面是 MDN 中对 Blob 的解释:
Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
实际上,Blob 对象是包含有只读原始数据的类文件对象。简单来说,Blob 对象就是一个不可修改的二进制文件。
(1)Blob 创建
可以使用 Blob() 构造函数来创建一个 Blob:new Blob(array, options)
其有两个参数:
- array:由
ArrayBuffer
、ArrayBufferView
、Blob
、DOMString
等对象构成的,将会被放进Blob
; - options:可选的
BlobPropertyBag
字典,它可能会指定如下两个属性- type:默认值为
""
,表示将会被放入到blob
中的数组内容的MIME
类型。 - endings:默认值为
transparent
,用于指定包含行结束符\n
的字符串如何被写入,不常用。
- type:默认值为
blob 对象上有两个属性:
- size:Blob 对象中所包含数据的大小(字节);
- type:字符串,认为该 Blob 对象所包含的 MIME 类型。如果类型未知,则为空字符串。
const blob = new Blob(["Hello World"], {type: "text/plain"});
console.log(blob.size); // 11
console.log(blob.type); // "text/plain"
// 以使用 URL.createObjectURL() 方法将 Blob 转化为一个 URL
const iframe = document.getElementsByTagName("iframe")[0];
iframe.src = URL.createObjectURL(blob);
(2)Blob 分片
Blob 对象内置了 slice() 方法用来将 blob 对象分片:const newBlob = oldBlob.slice([start [, end [, contentType]]]};
其有三个参数:
- start:设置切片的起点,即切片开始位置。默认值为 0,这意味着切片应该从第一个字节开始;
- end:设置切片的结束点,会对该位置之前的数据进行切片。默认值为blob.size;
- contentType:设置新 blob 的 MIME 类型。如果省略 type,则默认为 blob 的原始值。
文件的分片上传和断点续传会使用到 Blob 的分片功能。
2. File
文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。实际上,File 对象是特殊类型的 Blob,File 继承自 Blob,且可以用在任意的 Blob 类型的 context 中。Blob 的属性和方法都可以用于 File 对象。
注意:File 对象中只存在于浏览器环境中,在 Node.js 环境中不存在。
在 JavaScript 中,主要有两种方法来获取 File 对象:
<input>
元素上选择文件后返回的FileList
对象;- 文件拖放操作生成的
DataTransfer
对象;
每个 File 对象都包含文件的一些属性,这些属性都继承自 Blob 对象:
- lastModified:引用文件最后修改日期,为自
1970年1月1日0:00
以来的毫秒数; - lastModifiedDate:引用文件的最后修改日期;
- name:引用文件的文件名;
- size:引用文件的文件大小;
- type:文件的媒体类型(MIME);
- webkitRelativePath:文件的路径或 URL。
3. FileReader
FileReader 是一个异步 API,用于读取文件并提取其内容以供进一步使用。FileReader 可以将 Blob 读取为不同的格式。
- 使用 FileReader 构造函数来创建一个 FileReader 对象:
const reader = new FileReader()
FileReader 对象提供了以下方法来加载文件:
- readAsArrayBuffer():读取文件为 ArrayBuffer 数据对象;
- readAsBinaryString():读取文件为原始二进制数据;
- readAsDataURL():读取文件为 Base64 字符串;
- readAsText():读取文件为字符串;
示例:
const blob = new Blob(["Hello World"], {type: "text/plain"})
const reader = new FileReader()
reader.readAsArrayBuffer(blob)
reader.onload = (e) => {
const buffer = e.target?.result as ArrayBuffer
}
// 读取文本文件
const fileInput = document.getElementById("fileInput");
const reader = new FileReader();
fileInput.onchange = (e) => {
reader.readAsText(e.target.files[0]);
}
reader.onload = (e) => {
console.log(e.target.result); // 读取出选择的文件的文本
}
// 读取选择的图片生成 base64
const img = document.getElementById("myImg");
const fileInput = document.getElementById("fileInput");
const reader = new FileReader();
fileInput.onchange = (e) => {
reader.readAsDataURL(e.target.files[0]);
}
reader.onload = (e) => {
const base64 = e.target.result;
img.src = base64
}
当上传大文件时,可以通过 progress 事件来监控文件的读取进度:
const reader = new FileReader();
reader.onprogress = (e) => {
if (e.loaded && e.total) {
const percent = (event.loaded / event.total) * 100;
console.log(`上传进度: ${Math.round(percent)} %`);
}
};
4. ArrayBuffer
ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 的内容不能直接操作,只能通过 DataView 对象或 TypedArrray 对象来访问。这些对象用于读取和写入缓冲区内容。
ArrayBuffer 本身就是一个黑盒,不能直接读写所存储的数据,需要借助以下视图对象来读写;
那 ArrayBuffer 与 Blob 有啥区别呢?根据 ArrayBuffer 和 Blob 的特性,Blob 作为一个整体文件,适合用于传输;当需要对二进制数据进行操作时(比如要修改某一段数据时),就可以使用 ArrayBuffer。
-
创建:
new ArrayBuffer(bytelength)
-
方法:
- byteLength:表示 ArrayBuffer 的 byte 的大小
const buffer = new ArrayBuffer(16); console.log(buffer.byteLength); // 16
- slice: 用来截取 ArrayBuffer 实例,它返回一个新的 ArrayBuffer
const buffer = new ArrayBuffer(16); console.log(buffer.slice(0, 8)); // 8
视图对象一共提供 9 种类型的视图,每一种视图都是一种构造函数。如下:
元素 | 类型化数组 | 字节 | 描述 |
---|---|---|---|
Int8 | Int8Array | 1 | 8 位有符号整数 |
Uint8 | Uint8Array | 1 | 8 位无符号整数 |
Uint8C | Uint8ClampedArray | 1 | 8 位无符号整数 |
Int16 | Int16Array | 2 | 16 位有符号整数 |
Uint16 | Uint16Array | 2 | 16 位无符号整数 |
Int32 | Int32Array | 4 | 32 位有符号整数 |
Uint32 | Uint32Array | 4 | 32 位无符号整数 |
Float32 | Float32Array | 4 | 32 位浮点 |
Float64 | Float64Array | 8 | 64 位浮点 |
- 类型化数组的元素都是连续的,不会为空;
- 类型化数组的所有成员的类型和格式相同;
- 类型化数组元素默认值为 0;
TypedArray 实例的 buffer 属性会返回内存中对应的 ArrayBuffer对象,只读属性。
const a = new Uint32Array(8);
const b = new Int32Array(a.buffer);
console.log(a, b);
和数组的相互转换
const view = new Int8Array([1, 2, 3, 4, 5]);
view[0] = 10;
const array = Array.prototype.slice.call(view); // [10, 2, 3, 4, 5]
5. Object URL
Object URL(MDN定义名称)又称 Blob URL(W3C定义名称),是HTML5中的新标准。它是一个用来表示File Object 或 Blob Object 的URL。
其实 Blob URL/Object URL 是一种伪协议,允许将 Blob 和 File 对象用作图像、二进制数据下载链接等的 URL 源。
对于 Blob/File 对象,可以使用 URL 构造函数的 createObjectURL() 方法创建给出的对象的 URL 。这个 URL 对象表示指定的 File 对象或 Blob 对象。我们可以在 <img>
、<script>
标签中或者 <a>
和 <link>
标签的 href
属性中使用这个 URL。
// 例如:通过 createObjectURL 将选择的图片转成 URL 对象。注意与上面 FileReader.readAsDataURL 的区别
const fileInput = document.getElementById("fileInput");
const img = document.getElementById("myImg");
fileInput.onchange = (e) => {
img.src = URL.createObjectURL(e.target.files[0]);
};
6. Base64
Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。Base64 编码普遍应用于需要通过被设计为处理文本数据的媒介上储存和传输二进制数据而需要编码该二进制数据的场景。这样是为了保证数据的完整并且不用在传输过程中修改这些数据。
btoa("JavaScript") // 编码:'SmF2YVNjcmlwdA=='
atob('SmF2YVNjcmlwdA==') // 解码:'JavaScript'
const canvas = document.getElementById('canvas');
const dataURL = canvas.toDataURL('image/png'); // canvas 转换为 base64 图片
img.src = dataURL;
一些小的图片都可以使用 base64 格式进行展示,img标签和background的 url 属性都支持使用base64 格式的图片,这样做也可以减少 HTTP 请求。
7. 格式转化
- (1)ArrayBuffer → blob
const blob = new Blob([new Uint8Array(buffer, byteOffset, length)]);
- (2)ArrayBuffer → base64
const base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
- ((3)base64 → blob
const base64toBlob = (base64Data, contentType, sliceSize) => {
const byteCharacters = atob(base64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, { type: contentType });
return blob;
}
- ((4)blob → ArrayBuffer
function blobToArrayBuffer(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsArrayBuffer(blob);
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject;
});
}
- ((5)blob → base64
function blobToBase64(blob) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
- ((6)blob → Object URL
const objectUrl = URL.createObjectURL(blob);