切换语言为:繁体

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

  • 爱糖宝
  • 2024-07-28
  • 2053
  • 0
  • 0

前言

作为一名前端,在工作中会遇到很多二进制处理的问题。比如文件的上传、下载,都离不开对(File、Blob)数据的处理,但是大部分人对于这些都没有一个清晰的认识。

本篇文章总结了浏览器端的二进制以及有关数据之间的转化,整体内容有:

  1. 如何得到数据

  2. 认识File、Blob

  3. 如何对数据处理转换

  4. 转换后数据相互之间转换

  5. 如何将处理后的数据进行还原

为了更好的理解,总结了一张概括图,如下所示:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

下面针对每一个部分进行实践操作。

1. 输入

通常我们得到FileBlob对象,总结有这几种方式:

  1. 通过input标签

  2. 拖拽方式

  3. canvas获取

  4. 接口返回

如图:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

1.1 input

代码如下:

<input type="file" name="file" id="file">

const inputNode = document.getElementById('file')
inputNode.addEventListener('change', (e) => {
    const file = e.target.files[0]
})


得到File对象:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

1.2 拖拽

代码如下:

<div id="drag"></div>

const dragNode = document.getElementById("drag");
dragNode.ondragover = (e) => {
    e.preventDefault();
};

dragNode.ondrop = (e) => {
    e.preventDefault();
    const files = e.dataTransfer.files;
    console.log(files);
};


结果如下:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

1.3 canvas

代码如下:

<canvas id="canvas"></canvas>

const canvas = document.getElementById("canvas");

canvas.toBlob((blob) => {
    console.log("打印***blob", blob);
});


结果如下:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

1.4 接口

接口获取需要设置响应头为blob,这里以axios和fetch为例:

  • axios:

axios.post(url,{
  // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'blob',
})


  • fetch

fetch(url).then(res=>{
// 常用的有 json、text、arrayBuffer、blob
    return res.blob()
})


2 数据

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

经过输入得到File或者Blob,那么两者是什么,有什么关系,之间如何转换。

2.1 Blob

Blob 全称是binary large object,即二进制大对象,它是 JavaScript 中的一个对象,表示原始的类似文件的数据。

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

实际上,Blob 对象是包含有只读原始数据的类文件对象。简单来说,Blob 对象就是一个不可修改的二进制文件。

2.1.1 创建blob

可以使用 Blob() 构造函数来创建一个 Blob:

new Blob(array, options);


有两个参数:

  • array:由 ArrayBufferArrayBufferViewBlobDOMString 等对象构成的,将会被放进 Blob

  • options:可选的 BlobPropertyBag 字典,它可能会指定如下两个属性

    • type:默认值为 "",表示将会被放入到 blob 中的数组内容的 MIME 类型。

    • endings:默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入,不常用。

常见的 MIME 类型如下:

类型 描述
text/plain 纯文本文档
text/html HTML文档
text/javascript JavaScript文件
text/css CSS文件
application/json JSON文件
application/pdf PDF文件
application/xml XML文件
image/jpeg JPEG图像
image/png PNG图像
image/svg+xml SVG图像
audio/mpeg MP3文件
video/mpeg MP4文件

2.2 File

File对象提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。实际上,File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。Blob 的属性和方法都可以用于 File 对象。

注意:File 对象中只存在于浏览器环境中,在 Node.js 环境中不存在。

在 JavaScript 中,主要有两种方法来获取 File 对象:

  • <input> 元素上选择文件后返回的 FileList 对象;

  • 文件拖放操作生成的 DataTransfer 对象;

2.3 总结

  1. File是一种特殊的Blob,只存在于浏览器中,继承Blob中的方法和属性。

  2. 两者如何转换

    • File -> Blob:因为File是继承于Blob,不用进行转换

    • Blob -> File:通过new File([blob],fileName,{type:MIME})

3. 转换

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

通过Blob对象可以如何转换成自己想要的数据类型,有两种方式:

  • 使用createObjectURL,生成Object URL

  • 使用FileReader,生成DataURLBinaryStringTextArrayBuffer

下面分别实操下:

3.1 createObjectURL

URL 接口的 createObjectURL()  静态方法创建一个用于表示参数中给出的对象的 URL 的字符串。

URL 的生命周期与其创建时所在窗口的 document 绑定在一起。新对象 URL 代表指定的 File 对象或 Blob 对象。要释放对象 URL,需调用 revokeObjectURL()

无论是File还是Blob,可以直接调用URL.createObjectURL两者的结果是相同的。

使用同一张图片进行转换为例:

  1. File

通过input标签获取file对象,再进行转换:

<input type="file" name="file" id="file" />
const inputNode = document.getElementById("file");
  inputNode.addEventListener("change", (e) => {
    const file = e.target.files[0];
    console.log(
      "打印***file",
      URL.createObjectURL(file)
    );
})


结果:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

输入浏览器预览: 

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

  1. Blob

使用canvas的toBlob方法得到blob,再进行转换

<img src="./axios.png" alt="" srcset="" id="img" />
const cvs = document.createElement("canvas");
const imageNode = document.getElementById("img");
const ctx = cvs.getContext("2d");
cvs.width = imageNode.width;
cvs.height = imageNode.height;
ctx.drawImage(imageNode, 0, 0, cvs.width, cvs.height);
cvs.toBlob((blob) => {
console.log(
  "打印***blob",
  URL.createObjectURL(blob)
);
});


结果: 

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

输入浏览器预览: JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

3.1.1 Object URL

Object URL又称Blob URL(W3C定义名称),是HTML5中的新标准。它是一个用来表示File Object 或Blob Object 的URL。在网页中,我们可能会看到过这种形式的 blob: URL

其实Blob URL/Object URL 是一种伪协议,允许将 Blob 和 File 对象用作图像、二进制数据下载链接等的 URL 源。

对于 Blob/File 对象,可以使用 URL构造函数的 createObjectURL() 方法创建将给出对象的 URL。这个 URL 对象表示指定的 File 对象或 Blob 对象。我们可以在<img><script> 标签中或者 <a><link> 标签的 href 属性中使用这个 URL。

经典下载代码:

// 使用 URL.createObjectURL 创建一个 URL 对象 
const url = URL.createObjectURL(blob); 
// 创建一个 <a> 标签并设置下载属性 
const a = document.createElement('a'); 
a.href = url; 
a.download = 'hello.txt'; // 设置下载的文件名 
// 模拟点击 <a> 标签 
a.style.display = 'none'; 
document.body.appendChild(a); 
a.click(); 
// 移除 <a> 标签并释放 URL 对象 
document.body.removeChild(a); 
URL.revokeObjectURL(url);


3.2 FileReader

FileReader 允许异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

3.2.1 Data URL

Data URL是一种包含数据的URL,其中数据部分通常是使用Base64编码的。是一种将小数据嵌入到文档中的方式。它的格式如下:

data:[<mediatype>][;base64],<data>


  • <mediatype>:表示数据的媒体类型(MIME 类型),例如 text/plainimage/png。如果省略,默认值是 text/plain;charset=US-ASCII

  • ;base64:表示数据使用 Base64 编码。如果省略,数据部分应为 URL 编码的字符串。

  • <data>:表示实际的数据部分。

3.2.1.1 与Base64的关系

Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。Base64 编码普遍应用于需要通过被设计为处理文本数据的媒介上储存和传输二进制数据而需要编码该二进制数据的场景。这样是为了保证数据的完整并且不用在传输过程中修改这些数据。

在 JavaScript 中,有两个函数被分别用来处理解码和编码 base64 字符串:

  • atob():解码,解码一个 Base64 字符串;

  • btoa():编码,从一个字符串或者二进制数据编码一个 Base64 字符串。

例如:一个包含纯文本 "Hello, World!",使用btoa转换后得到的Data URL可以表示为:

data:text/html;base64,SGVsbG8sIFdvcmxkIQ==


JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

总结一下:

  • Data URL 是一种将数据嵌入到文档中的 URL 格式,其中数据部分通常使用 Base64 编码。

  • Base64 是一种将二进制数据转换为 ASCII 字符串的编码方式,用于在文本环境中传输二进制数据。

3.2.1.2 生成Data URL的两种方式
  1. canvas生成DataURL

const dataUrl = canvas.toDataURL();


结果如下: JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

  1. FileReader的readAsDataURL

const reader = new FileReader();

// Read as Data URL
reader.readAsDataURL(file);
reader.onload = function (e) {
    console.log("打印***e,reader", e, reader);
}


结果如下:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

注意:使用e或者reader实例都可获取结果

3.2.2 Text

const reader = new FileReader();

// Read as Data URL  
reader.readAsText(file);
reader.onload = function () {
    console.log("打印***text", reader.result);
}


新建txt文件,写入this is a text。 结果如下:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

注意:如果直接读取图片或其他文件,乱码

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

3.2.3 BinaryString

const reader = new FileReader();

//   Read as Binary String
reader.readAsBinaryString(file);
reader.onload = function () {
    console.log("打印***binaryString", reader.result);
}


结果如下: JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

3.2.4 ArrayBuffer

const reader = new FileReader();

// Read as ArrayBuffer
reader.readAsArrayBuffer(file);
reader.onload = function () {
    console.log("打印***binaryString", reader.result);
}


结果如下:

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

4. 四种格式相互转换

通过FileReader转换的四种数据,之间如何相互转换。以下是将 Data URLArrayBufferBinary StringText 之间相互转换的具体实现:

4.1 Data URL转换其他格式

4.1.1 Data URL -> ArrayBuffer

function dataURLToArrayBuffer(dataURL) {
    const binaryString = atob(dataURL.split(',')[1]);
    const len = binaryString.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
}


4.1.2 Data URL -> Binary String

function dataURLToBinaryString(dataURL) {
    return atob(dataURL.split(',')[1]);
}


4.1.3 Data URL -> Text

async function dataURLToText(dataURL) {
    const arrayBuffer = dataURLToArrayBuffer(dataURL);
    return arrayBufferToText(arrayBuffer);
}


4.2 ArrayBuffer转换其他格式

4.2.1 ArrayBuffer -> Data URL

function arrayBufferToDataURL(arrayBuffer, mimeType = 'application/octet-stream') {
    const bytes = new Uint8Array(arrayBuffer);
    const binaryString = bytes.reduce((data, byte) => data + String.fromCharCode(byte), '');
    return `data:${mimeType};base64,${btoa(binaryString)}`;
}


4.2.2 ArrayBuffer -> Binary String

function arrayBufferToBinaryString(arrayBuffer) {
    const bytes = new Uint8Array(arrayBuffer);
    return bytes.reduce((data, byte) => data + String.fromCharCode(byte), '');
}


4.2.3 ArrayBuffer -> Text

function arrayBufferToText(arrayBuffer) {
    const decoder = new TextDecoder('utf-8');
    return decoder.decode(new Uint8Array(arrayBuffer));
}


4.3 Binary String转换其他格式

4.3.1 Binary String -> ArrayBuffer

function binaryStringToArrayBuffer(binaryString) {
    const len = binaryString.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
}


4.3.2 Binary String -> Data URL

function binaryStringToDataURL(binaryString, mimeType = 'application/octet-stream') {
    return `data:${mimeType};base64,${btoa(binaryString)}`;
}


4.3.3 Binary String -> Text

function binaryStringToText(binaryString) {
    return decodeURIComponent(escape(binaryString));
}


4.4 Text转换其他格式

4.4.1 Text -> ArrayBuffer

function textToArrayBuffer(text) {
    const encoder = new TextEncoder();
    return encoder.encode(text).buffer;
}


4.4.2 Text -> Binary String

function textToBinaryString(text) {
    return unescape(encodeURIComponent(text));
}


4.4.3 Text -> Data URL

function textToDataURL(text, mimeType = 'text/plain') {
    const arrayBuffer = textToArrayBuffer(text);
    return arrayBufferToDataURL(arrayBuffer, mimeType);
}


通过上述函数,可以实现 Data URLArrayBufferBinary StringText 之间的相互转换。注意在处理不同编码格式和数据类型时,需要根据具体需求调整 TextDecoderTextEncoder 的编码参数。

5. FileReader转换后四种格式转换为blob格式

JavaScript 二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

要将 FileReader 转换后的四种格式(Data URLArrayBufferBinary StringText)转换为 Blob 格式,可以使用以下方法:

5.1 Data URL -> Blob

function dataURLToBlob(dataURL) {
    const byteString = atob(dataURL.split(',')[1]);
    const mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
    const ab = new ArrayBuffer(byteString.length);
    const ia = new Uint8Array(ab);
    for (let i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], { type: mimeString });
}


5.2 ArrayBuffer -> Blob

function arrayBufferToBlob(arrayBuffer, mimeType = 'application/octet-stream') {
    return new Blob([arrayBuffer], { type: mimeType });
}


5.3 Binary String -> Blob

function binaryStringToBlob(binaryString, mimeType = 'application/octet-stream') {
    const ab = new ArrayBuffer(binaryString.length);
    const ia = new Uint8Array(ab);
    for (let i = 0; i < binaryString.length; i++) {
        ia[i] = binaryString.charCodeAt(i);
    }
    return new Blob([ab], { type: mimeType });
}


5.4 Text -> Blob

function textToBlob(text, mimeType = 'text/plain') {
    return new Blob([text], { type: mimeType });
}


具体示例:

// Data URL to Blob
const dataURL = 'data:text/plain;base64,SGVsbG8gd29ybGQ=';
const blobFromDataURL = dataURLToBlob(dataURL);

// ArrayBuffer to Blob
const arrayBuffer = new Uint8Array([72, 101, 108, 108, 111]).buffer;
const blobFromArrayBuffer = arrayBufferToBlob(arrayBuffer);

// Binary String to Blob
const binaryString = 'Hello';
const blobFromBinaryString = binaryStringToBlob(binaryString);

// Text to Blob
const text = 'Hello world';
const blobFromText = textToBlob(text);


总结

通过上述整理可得,对于从文件到数据的转换可以形成一个完整的闭环。从文件-> 输入-> 数据 -> 转换能够形成一个直观的感受。

0条评论

您的电子邮件等信息不会被公开,以下所有项均必填

OK! You can skip this field.