一次性搞清楚Blob、File、FileReader、ArrayBuffer、Base64
Blob
Blob 全名是(Binary Large Object) 翻译过来就是 二进制类型的大对象 Blob 对象表示一个不可变、原始数据的类文件对象,一个 Blob 对象就是一个包含有只读原始数据的类文件对象。 Blob 对象中的数据并不一定得是 js 中的原生形式。 File 接口基于 Blob ,继承了 Blob 的功能,并且扩展支持了用户计算机上的本地文件。它的存在,允许我们可以通过 JS 直接操作二进制数据。还可以通过 Blob 设置二进制数据的 MIME 类型。
属性
Blob 对象含有两个属性:size 和 type 。
size表示数据的大小(单位是字节)type表明该Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串
创建 Blob
-
通过构造函数
var aBlob = new Blob( array, options );-
array:是一个由ArrayBuffer,ArrayBufferView,Blob,DOMString(DOMStrings会被编码为UTF-8)等对象构成的 数组。 -
options:一个可选的对象(用于设置Blob对象的属性(如:MIME类型)),包含以下两个属性type:默认值为"",它代表了将会被放入到blob中的数组内容的MIME类型。endings—— 默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个:native:代表行结束符会被更改为适合宿主操作系统文件系统的换行符transparent,代表会保持blob中保存的结束符不变
创建一个装填DOMString对象的Blob对象
let domStr = '<div> my name is constRen </div>'; // 一个包含 DOMString 的数组 let blob = new Blob([domStr], { type: 'text/html' }); // 得到 blob console.log('blob',blob);创建一个装填ArrayBuffer对象的Blob对象
let abf = new ArrayBuffer(6); let blob = new Blob([abf], { type: 'text/plain' }); console.log('blob', blob);创建一个装填ArrayBufferView对象的Blob对象
let typedArray = new Int8Array(8); let blob = new Blob([typedArray], { type: 'text/plain' }); console.log('blob', blob); -
-
通过
Blob.slice()此方法返回一个新的Blob对象,包含了原Blob对象中指定范围内的数据Blob.slice(start:number, end:number, contentType:string)`; 如:let newData = blob.slice(0, 5, 'text/plain'); // 注意 这儿的text/plain 不再是 一个对象了哦!!!start:开始索引,默认为0,如果传入的是一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说,-10将会是Blob的倒数第十个字节。如果传入的start的长度大于源Blob的长度,那么返回的将会是一个长度为0并且不包含任何数据的一个Blob对象。end:截取结束索引(不包括end),默认值就是它的原始长度。如果传入了一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说,-10将会是Blob的倒数第十个字节contentType:新Blob的MIME类型,默认为空字符串
-
通过
canvas.toBlob()语法: canvas.toBlob(callback, type, encoderOptions);callback:回调函数,可获得一个单独的Blob对象参数。type(可选):DOMString类型,指定图片格式,默认格式为image/pngencoderOptions(可选):Number类型,值在0与1之间,当请求图片格式为image/jpeg或者image/webp时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内,则使用默认值,其余参数将被忽略。 代码太多不好贴 贴个图片吧

上面介绍了那么多,其实用得少,下面说说平常开发经常用到的
应用场景
-
分片上传 通过
Blob.slice方法,可以将大文件分片,轮循向后台提交各文件片段,即可实现文件的分片上传。代码就不贴了,说下逻辑将要上传的
File对象,根据每片大小对文件进行分片,通过循环上传每片文件const file = new File(["a".repeat(1000000)], "test.txt"); const chunkSize = 40000; const url = "https://xxxxxxx"; async function chunkedUpload() { for (let start = 0; start < file.size; start += chunkSize) { console.log('start', start); const chunk = file.slice(start, start + chunkSize + 1); const fd = new FormData(); fd.append("data", chunk); // await fetch(url, { method: "post", body: fd }).then((res) => // res.text() // ); } } chunkedUpload();

方法
-
slice():这个上面讲过 -
stream():返回一个能读取blob内容的ReadableStream(可读的字节数据流)let domStr = '<div> my name is constRen </div>'; let blob = new Blob([domStr], { type: 'text/html' }); console.log('blob', blob); var buffer = blob.stream(); console.log('buffer', buffer);
-
text():返回一个Promise对象且包含blob所有内容的UTF-8格式的USVStringlet domStr = '<div> my name is constRen </div>'; let blob = new Blob([domStr], { type: 'text/html' }); console.log('blob', blob); var bufferPromise = blob.text(); console.log('bufferPromise', bufferPromise); blob.text().then(text => { console.log('text', text); }) async function fn() { var text = await blob.text(); console.log('text-async', text); }; fn();
-
arrayBuffer():返回一个Promise对象,且包含blob所有内容,并在ArrayBuffer中以二进制数据的形式呈现let domStr = '<div> my name is constRen </div>'; let blob = new Blob([domStr], { type: 'text/html' }); console.log('blob', blob); var bufferPromise = blob.arrayBuffer(); console.log('bufferPromise', bufferPromise); blob.arrayBuffer().then(buffer => { console.log('buffer', buffer); }) async function fn() { var buffer = await blob.arrayBuffer(); console.log('buffer-async', buffer); }; fn();
注意
Blob 对象是不可改变的。我们不能直接在一个 Blob 中更改数据,都是对一个 Blob 进行分割,从其中创建新的 Blob 对象。这就有点像 js 的字符串,无法更改字符串中的字符,但可以创建新的修改后的字符串
File
File 基于 Blo ,继承了 Blob 功能并将其扩展为支持用户系统上的文件。说白了就是 File 对象是特殊类型的 Blob
在 js 中,主要有两种方法来获取 File 对象:
-
<input>元素上选择文件后返回的FileList对象;<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="file"> <script> const myInput = document.querySelector('input'); myInput.onchange = function (e) { console.log(' e.target.files', e.target.files); } </script> </body> </html> -
文件拖放操作生成的
DataTransfer对象;<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p draggable="true">拖动</p> <script> const myP = document.querySelector('p'); myP.ondrag = function (e) { e.preventDefault(); console.log('e', e.dataTransfer.files); } </script> </body> </html>
属性
lastModified(只读):返回当前File对象所引用文件最后修改时间,自UNIX时间起始值(1970 年 1 月 1 日 00:00:00 UTC)以来的毫秒数。lastModifiedDate(只读):返回当前File对象所引用文件最后修改时间的Date对象。name(只读):返回当前File对象所引用文件的名字。size(只读):返回文件的大小。webkitRelativePath(只读):返回File相关的path或URL(该特性是非标准的,请尽量不要在生产环境中使用它!)type(只读):返回文件的MIME类型
方法
File 接口没有定义任何方法,但是它从 Blob 接口继承了以下方法
File.slice(start:number, end:number, contentType:string)
FileReader
FileReader 说直白点就是一个可以读取 Blob 内容的工具
常用方法
onload:处理load事件。该事件在读取操作完成时触发readAsArrayBuffer∶读取指定Blob中的内容,完成之后,result属性中保存的将是被读取文件的ArrayBuffer数据对象;readAsBinaryString︰读取指定Blob中的内容,完成之后,result属性中将包含所读取文件的原始二进制数据;readAsDataURL︰读取指定Blob中的内容,完成之后,result属性中将包含一个data: URL格式的Base64字符串以表示所读取文件的内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file">
<script>
const myInput = document.querySelector('input');
myInput.onchange = function (e) {
console.log(' e.target.files', e.target.files);
const file = e.target.files[0];
var fileRead = new FileReader();
// Base64
fileRead.readAsDataURL(file);
fileRead.onload = function () {
console.log('fileRead.result', fileRead.result);
}
}
</script>
</body>
</html>

readAsText∶读取指定Blob中的内容,完成之后,result属性中将包含一个字符串以表示所读取的文件内容。
let blob = new Blob(['abcdefg'], { type: 'text/plain' });
console.log('blob', blob);
let blob2 = blob.slice(0, 5, 'text/plain');
console.log('blob2', blob2);
var fileRead = new FileReader();
fileRead.readAsText(blob2);
fileRead.onload = function () {
let res = fileRead.result;
console.log('res', res);
};

上面的方法除了各自的作用不同之外,其他都差不多,也就没有没有一一举例。
ArrayBuffer
ArrayBuffer 用来表示通用的、固定长度的原始二进制数据缓冲区,我们不能直接操作 ArrayBuffer 的内容,而是要通过 TypedArray(类型数组对象)或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。
他们直接的关系是这样的

TypedArray 视图和 DataView 视图的区别主要是字节序,前者的数组成员都是 同一个数据类型,后者的数组成员可以是 不同的数据类型。

语法
new ArrayBuffer(bytelength)
参数:只有一个参数,即 bytelength 表示要创建数组缓冲区的大小(以字节为单位)
TypedArray 读写 buffer



DataView 读写 buffer
DataView 实例提供了以下方法来写入内存,它们都接受两个参数,第一个参数表示开始写入数据的字节序号,第二个参数为写入的数据:


createObjectURL
简单来说就是一个用来表示 File Object 或 Blob Object 的 URL
用法
URL.createObjectURL(file)
就长这样

有生就有灭
URL.revokeObjectURL(objectURL) 方法用来释放一个之前已经存在的、通过调用 URL.createObjectURL() 创建的 URL 对象
参数:即 objectURL ,URL.createObjectURL() 创建的 URL 对象
这儿写一个使用 createObjectURL 和 FileReader 分别实现同步和异步生成图片的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file">
<script>
const myInput = document.querySelector('input');
myInput.onchange = function (e) {
const file = e.target.files[0];
var img = new Image();
// 这是同步
// img.src=URL.createObjectURL(file);
// 异步
var fileRead = new FileReader();
fileRead.readAsDataURL(file);
fileRead.onload = function () {
img.src = fileRead.result
};
document.body.appendChild(img)
}
</script>
</body>
</html>
Base64
Base64是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。
在 js 中,有两个函数被分别用来处理 解码和编码 base64 字符串:
atob():解码,解码一个Base64字符串;btoa():编码,从一个字符串或者二进制数据编码一个Base64字符串。
使用场景
-
将
canvas画布内容通过Base64生成图片<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <canvas width="200" height="200"></canvas> <script> const canvas = document.querySelector('canvas'); let context = canvas.getContext('2d'); context.fillStyle = 'red'; context.fillRect(0, 0, 200, 200); const dataUrl = canvas.toDataURL(); console.log('dataUrl', dataUrl); </script> </body> </html>

-
将获取的图片文件,通过
Base64生成图片fileRead.readAsDataURL(file) // 是不是很眼熟啊?
总结
我把这些关系 理了一下
;
参考资料:
developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/…
转载自:https://juejin.cn/post/7233067863500996665