在前端开发中,经常会有对文件的操作,会用到Flie,Blob,Base64等文件对象类型,通过查阅MDN弄清了他们之间的关系,和它们之间的转换方法,妈妈再也不用担心文件对象操作的问题了!
File对象
通常情况下, File对象是来自用户在一个
<input>
元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象,或者来自 HTMLCanvasElement 上的 mozGetAsFile() API。File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。比如说, FileReader, URL.createObjectURL(), createImageBitmap(), 及 XMLHttpRequest.send() 都能处理 Blob 和 File。
通过input获取文件对象(详见:在web应用程序中使用文件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="app">
<input type="file" id="file">
</div>
</body>
<script>
var inputDom = document.getElementById('file')
inputDom.addEventListener('change', (event) => {
console.log('文件对象', event.target.files[0]);
});
</script>
</html>
Blob对象
Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
Blob 表示的不一定是JavaScript原生格式的数据。File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。
要从其他非blob对象和数据构造一个 Blob,请使用 Blob() 构造函数。
所以我们从File对象要得到Blob对象,可用Blob构造函数。
//接上面的代码
var inputDom = document.getElementById('file')
inputDom.addEventListener('change', (event) => {
console.log('文件对象', event.target.files[0]);
var fileObj = event.target.files[0]
var blobObj = new Blob([fileObj],{type:fileObj.type})
console.log('Blob对象', blobObj);
});
Base64
Base64 是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。Base64 这个词出自一种 MIME 数据传输编码。
readAsDataURL 方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成DONE,并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。
//接上面的代码
var reader = new FileReader();
reader.onload = function (evt) {
console.log('Base64', evt.target.result);
};
reader.readAsDataURL(fileObj);
可以看出转base64后编码尺寸增加。
每一个Base64字符实际上代表着6比特位。因此,3字节(一字节是8比特,3字节也就是24比特)的字符串/二进制文件可以转换成4个Base64字符(4x6 = 24比特)。
这意味着Base64格式的字符串或文件的尺寸约是原始尺寸的133%(增加了大约33%)。如果编码的数据很少,增加的比例可能会更高。例如:字符串"a"的length === 1进行Base64编码后是"YQ=="的length === 4,尺寸增加了300%。
所以在实际使用中,一般小图标可用base64来展示,大的文件放在服务器,通过url形式展示。
问题:如何从Base64转到blob?
通过查阅资料得到了下面的方法
function dataURLtoBlob(dataurl) {
//传入base64编码
var arr = dataurl.split(','),//拆分
mime = arr[0].match(/: (.*?);/)[1],//获取类型
bstr = atob(arr[1]), //获取二进制
n = bstr.length, //获取长度
u8arr = new Uint8Array(n);//获取二进制编码数组
while (n--) {
u8arr[n] = bstr.charCodeAt(n);//返回指定位置的字符的 Unicode 编码
}//获取TypedArray
return new Blob([u8arr], { type: mime });//构造函数创建Blob
}
以前用这个方法并不知道其中的道道,通过断点调试及查阅资料可以得知如下解析:
- 通过
split
方法把base64分成两部门,头(包含源文件类型信息),ASCII 字符串(文件数据)部分。 arr[0].match(/: (.*?);/)[1]
通过正则获取文件类型。atob()
函数能够解码通过base-64编码的字符串数据,获取二进制数据“字符串”。n = bstr.length, u8arr = new Uint8Array(n);new Uint8Array(length);
// 创建初始化为0的,包含length个元素的无符号整型数组,就是说把二进制数据“字符串”拆开放进u8arr数组中。while (n--) { u8arr[n] = bstr.charCodeAt(n); }
调用charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。获取到的是一个类型化数组(TypedArray)对象描述了一个底层的二进制数据缓冲区(binary data buffer)的一个类数组视图(view)。相当于ArrayBuffer实例。new Blob([u8arr], { type: mime });
用构造函数创建Blob对象,完成了Base64到Blob的转换
总结
- Blob对象表示一个不可变、原始数据的类文件对象。
- File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。
- 可以用Blob构造函数把Flie对象转换为Blob对象,可以通过FileReader.readAsDataURL()方法获取文件的data:URL格式的字符串(base64编码)。
- base64转Blob需先将其拆分,将ASCII 字符串转换为TypedArray,再通过Blob构造函数创建Blob对象。