一次性搞清楚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/png
encoderOptions(可选)
: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
格式的USVString
let 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