任意内容转base64及Data URL

Blob对象和File对象

Blob对象是不可变的原始数据, 可以读取为文本或二进制数据.
File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。比如说, FileReader, URL.createObjectURL(), createImageBitmap(), 及 XMLHttpRequest.send() 都能处理 Blob 和 File。

new Blob([text1, text2], { type: 'application/octet-stream' });
new File([file], 'rename.mp4'); // 复制文件并临时重命名

代码

/**
 * 演示使用a标签生成下载, 命名下载文件名, 数据转base64
 * Data URLs 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身:
 * data:[<mediatype>][;base64],<data>
 */
import { Component } from 'react';
import Button from '@/components/Button';
import Code from '@/components/Code';

class Demo extends Component {
    handleClick(event) {
        let a = document.createElement('a');
        let text = 'ABC你好'; // 要存放的utf-8文本, 无法使用btoa转base64编码
        switch (event.target.innerText) {
            case '使用URI编码文本后再base64编码的Data URLs': {
                a.href = `data: application/octet-stream; base64,${btoa(encodeURI(text))}`; // 文本中含有汉字而无法使用btoa转义, 因此使用URI编码文本
                break;
            }
            case '使用utf-8编码文本的Data URLs': {
                a.href = `data: application/octet-stream; utf-8,${text}`; // 不使用base64, 使用utf-8编码保存文件
                break;
            }
            /* 在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。
             * 当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放。
             */
            case '使用Blob创建ObjectURL本地链接': {
                let blob = new Blob([text, 123], { type: 'application/octet-stream' });
                console.log(blob); // Blob { size: 12, type: "application/octet-stream" }
                a.href = URL.createObjectURL(blob);
                console.log(a.href); // 一个以"blob:"开头的URL地址
                break;
            }
            case '使用FileReader将Blob编码为Data URLs': {
                let reader = new FileReader();
                reader.addEventListener('loadend', event => {
                    a.href = event.target.result;
                    console.log(a.href); // Data URLs
                    // 这里是异步的, 所以要重复操作
                    a.download = '文件.end'; // 8位位组八位字节流可以自定义文件后缀
                    a.click(); // 遗憾的是, 无法感知文件下载完成事件, 从而无法主动释放Blob对象创建的ObjectURL
                });
                let blob = new Blob([text], { type: 'application/octet-stream' });
                reader.readAsDataURL(blob);
                break;
            }
        }
        a.download = '文件.end'; // 8位位组八位字节流可以自定义文件后缀
        a.click(); // 遗憾的是, 无法感知文件下载完成事件, 从而无法主动释放Blob对象创建的ObjectURL
    }
    render() {
        return (
            <div>
                <Button onClick={_ => this.handleClick(_)}>使用URI编码文本后再base64编码的Data URLs</Button>
                <Button onClick={_ => this.handleClick(_)}>使用utf-8编码文本的Data URLs</Button>
                <Button onClick={_ => this.handleClick(_)}>使用Blob创建ObjectURL本地链接</Button>
                <Button onClick={_ => this.handleClick(_)}>使用FileReader将Blob编码为Data URLs</Button>
            </div>
        );
    }
}

export default (
    <div>
        <Demo />
        <Code>{require('!raw-loader!.').default}</Code>
    </div>
);

前端

缺陷:函数参数有限,所以大数据会抛出错误RangeError: Maximum call stack size exceeded。

function String2ArrayBuffer(str, callback) {
    var b = new Blob([str]);
    var f = new FileReader();
    f.onload = function (e) {
        callback(e.target.result);
    }
    f.readAsArrayBuffer(b);
}

String2ArrayBuffer('你好abc', function (buf) {
    const base64String = window.btoa(String.fromCharCode(...new Uint8Array(buf)));
    console.log(base64String);
});

修复:

function String2ArrayBuffer(str, callback) {
    var b = new Blob([str]);
    var f = new FileReader();
    f.onload = function (e) {
        callback(e.target.result);
    }
    f.readAsArrayBuffer(b);
}

function arrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}

String2ArrayBuffer('你好abc', function (buf) {
    const base64String = arrayBufferToBase64(buf);
    console.log(base64String);
});

Node.js

Buffer
posted @ 2020-09-29 12:07  develon  阅读(1132)  评论(0编辑  收藏  举报