平时工作和学习中,会遇到一些对二进制对象的操作,总是对Blob、File、FileReader、ArrayBuffer、Buffer、URL.createObjectURL等API傻傻分不清,希望通过这篇文章做一个梳理。
Blob、File、ArrayBuffer
都是二进制数据对象,可以使用FileReader、URL.createObjectURL
对二进制对象读取转换
1、Blob
Blob
(Binary Large Object,二进制大对象)对象表示一个不可变
、原始数据的类文件对象,它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream
来用于数据操作。
Blob 表示的不一定是 JavaScript 原生格式的数据。File
接口基于 Blob
,继承了 Blob 的功能并扩展
创建 blob 对象
1、new Blob()
var blob = new Blob( array, options )
参数:
-
array:是一个由
ArrayBuffer
,ArrayBufferView
,Blob
,DOMString
等对象构成的Array
,它将会被放进Blob
;(DOMString可以认为就是字符串,stack overflow有相关问答:What is a DOMString really?) -
options:可以指定两个属性,
type
,默认值为""
,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。endings
,默认值为"transparent"
,用于指定包含行结束符\n
的字符串如何被写入。
示例:
js
// 通过buffer创建
const buffer = new ArrayBuffer(8); // 创建了一个 8 字节的缓冲区
const blob1 = new Blob([buffer], { type: "application/octet-stream" });
// 通过字符串创建
const blob2 = new Blob(['<a id="a">hey!</a>'], { type: "text/html" });
// 通过数字创建
const blob3 = new Blob([2], { type: "text/plain" });
// 通过ArrayBufferView创建
const view = new Int8Array(8); // 创建1字节视图
const blob4 = new Blob([view], { type: "application/octet-stream" });
// 通过blob创建blob
const blob5 = new Blob([blob2]);
console.log(blob1, blob2, blob3, blob4, blob5);
2、blob.slice()
var blob = instanceOfBlob.slice([start [, end [, contentType]]]);
参数:
start
:开始下标,end
:结束下标,不包括这个位置contentType
:设置type属性,默认值是一个空的字符串。
Blob不可变,不能直接修改,但是可以通过slice把blob分割,创建出新的blob,使用此方法可以对大文件分片上传
示例:
js
const blob = new Blob(["FileBlobArrayBuffer"], { type: "text/plain" });
// slice返回一个新的 Blob 对象,它包含了原始 Blob 对象的某一个段的数据。
const b1 = blob.slice(0, 4);
const b2 = blob.slice(4, 8);
const b3 = blob.slice(8);
// text() 方法返回一个 Promise 对象
b1.text().then((t1) => {
console.log(t1); // 'File'
});
b2.text().then((t2) => {
console.log(t2); // 'Blob'
});
b3.text().then((t3) => {
console.log(t3); // 'ArrayBuffer'
});
转换处理 blob 对象
1、FileReader
FileReader
对象允许 Web 应用程序异步读取
存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File
或 Blob
对象指定要读取的文件或数据。
-
readAsText():
将Blob
或File
对象转根据特殊的编码格式异步
读取转化为字符, 只有当执行完成后才能够查看到结果,在onload
或onloadend
的事件中处理转化后的结果示例:
js
const obj = { count: 1 };
const blob = new Blob([JSON.stringify(obj)], { type: "application/json" });
// 创建一个文件读取器
const fileRead = new FileReader();
//读取blob对象
fileRead.readAsText(blob);
// 文件成功读取,执行load 事件
fileRead.onload = function (e) {
console.log(e.target.result); // {"count":1}
console.log(fileRead.result); // {"count":1}
};
// 文件读取完成,无论成功与否,执行loadend 事件
fileRead.onloadend = function (e) {
console.log(e.target.result); // {"count":1}
console.log(fileRead.result); // {"count":1}
};
-
readAsDataURL():
将Blob
或File
对象。读取操作完成的时候,readyState
会变成已完成DONE
,并触发loadend
事件,同时result
属性将包含一个data:
URL 格式的base64
编码字符串。示例:
html
<!-- html -->
<input class="input" type="file" />
<img class="img" src="" height="200" alt="Image preview..." />
js
const imgEl = document.querySelector(".img");
const inputEl = document.querySelector(".input");
const fileReader = new FileReader();
inputEl.onchange = function (e) {
const file = this.files[0];
// file:File对象,继承自Blob
if (file) {
fileReader.readAsDataURL(file);
}
};
fileReader.onload = function () {
console.log(fileReader.result); //`data:`URL 格式, base64编码字符串
imgEl.src = fileReader.result;
};
-
readAsArrayBuffer():
将Blob
或File
对象。读取操作完成的时候,readyState
会变成已完成DONE
,并触发loadend
事件,同时result
属性将包含一个ArrayBuffer
对象数据。示例:
js
const blob = new Blob(["blob"], { type: "application/json" });
const fileReader = new FileReader();
fileReader.readAsArrayBuffer(blob);
fileReader.onload = function () {
console.log(this.result); // ArrayBuffer 对象
};
2、URL.createObjectURL
URL.createObjectURL()
静态方法会创建一个 Blob URL
,这个新的 URL 表示指定的 File
对象或 Blob
对象。
这个Blob URL 可以用于img.src
作为图片展示,
示例:
html
<!-- html -->
<input class="input" type="file" />
<img class="img" src="" height="200" alt="Image preview..." />
js
const imgEl = document.querySelector(".img");
const inputEl = document.querySelector(".input");
inputEl.onchange = function (e) {
const file = this.files[0];
// file : File对象 ,继承自Blob
if (file) {
const url = URL.createObjectURL(file);
console.log(url); // blob:null/b1a2bc4a-1f33-452f-8f88-8b4efee6138d
imgEl.src = url;
}
};
也能作为二进制数据下载链接
示例:
html
<!-- html -->
<input class="input" type="file" />
<img class="img" src="" height="200" alt="Image preview..." />
<a class="download">下载图片</a>
js
const imgEl = document.querySelector(".img");
const inputEl = document.querySelector(".input");
const aEl = document.querySelector(".download");
inputEl.onchange = function (e) {
const file = this.files[0];
// file : File对象 ,继承自Blob
if (file) {
const url = URL.createObjectURL(file);
console.log(url); // blob:null/b1a2bc4a-1f33-452f-8f88-8b4efee6138d
imgEl.src = url; // 图片显示
aEl.download = "js.jpg";
aEl.href = url; // 下载链接
}
};
3、Response
Response对象可以使用new Response创建,但通常更可能遇到的情况是,其他的 API 操作返回了一个 Response 对象。通过new Response(blob)
传入一个blob对象,可以通过以下实例方法进行转换:
arrayBuffer()
:返回一个被解析为ArrayBuffer
格式的 Promise 对象。blob()
:并返回一个被解析为Blob
格式的 Promise 对象。json()
:并返回一个被解析为json
的 Promise 对象。text()
:并返回一个被解析为文本
的 Promise 对象。
2、File
File对象 通常产生于<input>
元素上选择文件后返回的 FileList
对象,或者自由拖放操作生成的 DataTransfer
对象。
File
对象继承自Blob
,是特殊类型的 Blob
,且可以用在任意的 Blob 类型的 context 中。比如说, FileReader
, URL.createObjectURL()
, 及 XMLHttpRequest.send()
都能处理 Blob
和 File
1、<input>元素选择文件
html
<!-- html-->
<input class="input" type="file" />
js
const inputEl = document.querySelector(".input");
inputEl.onchange = function (e) {
const file = this.files[0];
console.log(file);
};
2、拖放文件
html
<!-- -->
<div class="drop-wrapper"></div>
js
const dropEl = document.querySelector(".drop-wrapper");
dropEl.ondragover = (e) => {
e.preventDefault(); // 阻止默认行为,否则浏览器会新开一个标签页
};
dropEl.ondrop = (e) => {
e.preventDefault(); // 阻止默认行为
console.log(e);
const files = e.dataTransfer.files;
console.log(files);
};
3、转换处理File
File
接口没有定义任何方法,它继承了Blob
接口,可以调用Blob 的实例方法,同样可以使用 FileReader
, URL.createObjectURL()
等方法转换 File
3、ArrayBuffer
详解见阮一峰老师的 《ECMAScript 6 入门》ArrayBuffer