切換語言為:簡體

JavaScript 二進制及其相關轉換全總結(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)

  • 爱糖宝
  • 2024-07-28
  • 2052
  • 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.