我又懂了File Blob Base64

269 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

项目中经常涉及到文件的操作,每次都得百度,这次还是整体学习一下吧。

Base64

Base64 是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。这个词出自一种 MIME 数据传输编码

javascript 中:atob() 函数能够解码通过 base-64 编码的字符串数据。btoa() 能够从二进制数据”字符串“创建一个 base-64 编码的 ASCII 字符串。atob btoa 均使用字符串,想使用 ArrayBuffer,请往后看。

Base64会增加编码尺寸

每一个 Base64 字符实际上代表6比特位。3字节(1字节是8比特)的字符串/二进制文件可以转换成4个Base64字符。这意味着 Base64 格式的字符串或文件的尺寸约是原始尺寸的133%,大约增加了33%。如果编码很少,增加的比例可能会更高。例如: 'a' 进行 Base64 编码后是 ”YQ==“,尺寸增加了300%。


Blob

表示一个不可变、原始数据的类文件对象。它的数据可以按文本或者二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
Blob 表示的并不一定是 Javascript 的原生格式的数据。 File 接口基于Blob,继承了Blob的功能并将其扩展使其支持用户系统上的文件。

constructor

new Blob(blobParts, options)

blobParts 是 Blob | BufferSource | String 类型的数组

options 可选对象:

        type Blob 类型,通常是MIME

        endings 是否转换换行符,使Blob对应于当前操作系统的换行符( \r\n 或 \n )。默认是“transparent”,啥也不做。也可是 "native" 转换。

属性

Blob.size 所包含数据的大小(字节)。

Blob.type 数据的 MIME 类型。类型未知,则该值为空字符串。

方法

Blob.slice([start [,end[, contentType]]]) 截取数据,返回一个新的 Blob。

Blob.stream() 返回一个能读取 blob 内容的 ReadableStream

Blob.text() 返回一个 promise 且包含 blob 所有内容的 UTF-8 格式的 USVString

Blob.arrayBuffer() 返回一个 promise 且包含 blob 所有内容的二进制格式 ArrayBuffer

// 从 Blob 中提取数据:除了 text 和 arrayBuffer, 还有一种方法是使用 FileReader
var reader = new FileReader();
reader.addEventListener("loadend", function(){
    // reader.result 包含被转化为类型数组 typed array 的 blob
})
reader.readAsArrayBuffer(blob);

// 另一种方法是使用 Response 对象
var text = await (new Response(blob)).text()

Blob 用作 URL

<!-- 下载文件 -->
<a download="hello.txt" href="#" id="link">下载</a>

<script>
let blob = new Blob(["hello world"], {type: "text/plain"})
link.href = URL.createObjectURL(blob) // 需要介意内存, 需要使用revoke撤销它

URL.revokeObjectURL(link.href) // 释放 Blob 占用的内存
</script>

Blob 转 Base64

URL.createObjectURL 的一个替代方法是将 Blob 转换为 base64 编码的字符串。Base64 安全“可读”。但是对大的Blob进行编码时,性能和内存会有损耗。

let link = document.createElement('a');
link.download = "hello.txt"

let blob = new Blob(['hello world'], {type: 'text/plain'})

let reader = new FileReader();
reader.readAsDataURL(blob); // blob 转换成 base64 并调用 onload

reader.onload = function(){
    link.href = reader.result;
    link.click()
}

Img 转 Blob

let img = document.querySelector('img');

let canvas = document.createElement('canvas');
canvas.width = img.clientWidth;
canvas.heigth = img.clientHeight;

let context = canvas.getContext('2d');

context.drawImage(img, 0, 0);
canvas.toBlob(function(blob){
    let link = doucment.createElement('a');
    link.download = 'example.png';
    link.href = URL.createObjectURL(blob);
    link.click()
    
    URL.revokeObjectURL(link.href)
}, 'image/png')

Blob 转 ArrayBuffer

const bufferPromise = await blob.arrayBuffer()

blob.arrayBuffer().then(buffer => /* 处理 ArrayBuffer */)

Blob 转 Stream

当我们需要处理大型blob时,将其转换成 stream 是非常有用的。

const readableStream = blob.stream();
const stream = readableStream.getReader();

while(true){
    let { done, value } = await stream.read();
    if (done) {
        break
    }
    console.log(value);
}

File

File 对象是特殊类型的 Blob,可以用在任意的 Blob 类型的 context 中。比如说:FileReader | URL.createObjectURL | createImageBitmap() | XMLHttpRequest.send() 都能处理 Blob 和 File

constructor

new File(bits, name[, options])

bits 包含 ArrayBuffer | ArrayBufferView | Blob | DOMString 对象的 Array 或者这些对象的组合。这是 UTF-8 编码的文件内容

name USVString,表示文件名称或文件路径。

options 选项对象,包含文件的可选属性。可用的选项如下:

    type: DOMString,表示文件的 MIME 类型,默认是 ”“。

    lastModified 数值( 时间戳),默认是 Date.now()。

属性

lastModified 

lastModifiedDate

name

size

webkitRelativePath

type MIME type

方法

没有定义任何方法,从 Blob 继承了 slice 方法

FileReader 🥝

FileReader 是一个对象,其唯一目的是从 Blob(因此也能从 File) 对象中读取数据。它用事件来传递数据,因为从磁盘中读取数据可能比较费时间。

constructor

new FileReader() 没有参数

方法

readAsArrayBuffer(blob)  将数据读取为二进制格式的 ArrayBuffer 。用于二进制文件,执行低级别的二进制操作。比如:切片(slice)之类的高级别的操作。

readAsText(blob, [encoding]) 将数据读取为给定编码(default:UTF-8)的文本字符串。用于文本文件,当我们想获取字符串的时候。

readAsDataURL(blob)  读取二进制数据,并将其编码成 base64 的 data url。用于想在src中使用此数据。

abort() 取消操作。

读取中有以下事件:

loadstart  开始加载

progress  读取中

load 读取完成,没有error

abort  调用了 abort()

error 出现 error

loadend  读取完成,不管成功还是失败

读取完成后,可以用以下方式获取结果:

reader.result

reader.error

// <input onchange="readFile(this)"/>

function readFile(input) {
    let file = input.files[0];
    let reader = new FileReader();
    
    reader.readAsText(file);
    reader.onload = function () {
        console.log(reader.result)
    }
    
    reader.onerror = function () {
        console.log(reader.error)
    }
}