iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 30
0

DAY 30. JavaScript Blob, Buffer

當我們開始有操作檔案的需求時,就會需要認識Blob, Buffer
例如我們在DAY 29. JavaScript Canvas 處理中將Canvas轉為檔案並上傳。

Blob

Blob(Binary Large Object)物件代表了一個相當於檔案(原始資料)的不可變物件。Blob 中的資料並不一定是 JavaScript 原生的格式。File 介面基於 Blob,繼承 blob 並擴充其功能以支援操作使用者系統上的檔案。

引自 Blob Web APIs | MDN

建構式

/*
 * array: blob 資料片段的array
 * options: 選擇性物件,可以設定 type與 endings屬性
 * 其中type屬性代表將被放進 Blob 物件的陣列內容之 MIME 類型
 * endings代表"\n"換行字元的字串要如何輸出,可選擇字串'transparent', 'native'
 * transparent 預設值:保留 Blob 物件中資料的換行字元
 * native 換行字元會被轉為目前作業系統的換行字元編碼
 */
const blob = Blob(array, options)

Buffer

Buffer在JavaScript中稱為ArrayBuffer
ArrayBuffer物件是一種表示通用、固定大小的原始二進制資料緩衝。
且無法直接修改ArrayBuffer的內容,欲修改其內容必須通過設定 TypeArray解讀、修改ArrayBuffer。

建構式

/*
 * length表示建立的緩衝陣列大小,以位元byte計算
 */
const buf = new ArrayBuffer(length)

// buf 將得到一個指定長度的ArrayBuffer實例,其初始直接為0

Blob, ArrayBuffer之間的關係

Blob是裝載數據的二進制資料,ArrayBuffer是能夠裝載Blob資料的原始緩衝區。
ArrayBuffer不能通過js直接讀寫,需依賴操作TypeArray修改。

什麼是 TypeArray ?

A TypedArray object describes an array-like view of an underlying binary data buffer. There is no global property named TypedArray, nor is there a directly visible TypedArray constructor. Instead, there are a number of different global properties, whose values are typed array constructors for specific element types, listed below. On the following pages you will find common properties and methods that can be used with any typed array containing elements of any type.

引自 TypeArray - JavaScript | MDN

操作

以下開始介紹如何通過 TypeArray來設定 ArrayBuffer,
以及Blob, ArrayBuffer互相轉換的操作方式。

ArrayBuffer to Blob

const arrayBuffer = new ArrayBuffer(32)
console.log(arrayBuffer)    // [object ArrayBuffer]

/*
 * 特別注意在此作為參數的arrayBuffer必須使用array包覆
 */
const blob = new Blob([arrayBuffer])
console.log(blob)
// [object Blob] {
//   size: 32,
//   slice: function slice() { [native code] },
//   type: ""
// }

Blob to ArrayBuffer

// 建立一個範例用的Blob
const ab = new ArrayBuffer(8)
const bl = new Blob([ab])

const fr = new FileReader()
fr.addEventListener('load', function(event) {
    console.log(this.result)    // [object ArrayBuffer]

    /*
     * 接著如果想真正讀出ArrayBuffer內容
     * 必須將其轉成Uint8Array, 原因是
     * 在ArrayBuffer中每個字節 = 8位元, 因此須先轉為Unit8Array
     */
    const ab = this.result
    const u8 = new Uint8Array(ab)
    for(let i of u8) {
      console.log(i)    // 0 0 0 0 0 0 0 0
    }
})
fr.readAsArrayBuffer(bl)

操作範例

前端實際運用Blob, ArrayBuffer的場景較少
在這邊再次使用Canvas作為範例。

// 建立一個範例用圖
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = 150
canvas.height = 150
ctx.strokeStyle = 'rgba(255, 0, 0, .5)'
ctx.arc(75, 75, 50, 0, Math.PI * 2, false)
ctx.lineWidth = '5'
ctx.stroke()
// ----  範例圖繪製完畢

// 首先將Canvas轉為 DataURL
const dataURL = canvas.toDataURL('image/png')

// 取出資料並使用 atob 將資料轉為base64的字串
const blobBin = atob(dataURL.split(',')[1])

console.log(blonBin)

// 取得 mine
const mime = dataURL.split(',')[0].split(':')[1].split(';')[0]
console.log(mime)   // "image/png"

// 建立一個array容器放charCode
const arr = []
for (let i = 0; i < blobBin.length; i++) {
    arr.push(blobBin.charCodeAt(i))
}

// 將基礎arr 轉為 ArrayBuffer (usign integer 8): Uint8Array
const u8 = new Uint8Array(arr)
const file = new Blob([u8], { type: mime })
console.log(file)
// [object Blob] {
//   size: 3860,
//   slice: function slice() { [native code] },
//   type: "image/png"
// }

/*
 * 接著這個 file就可以被 FromData使用
 */
const formData = new FormData()
formData.append('file', file, 'test.png')
for(let field of formData) {
    console.log(field)
    // ["file", [object File] {
    //   lastModified: 1514901149956,
    //   lastModifiedDate: [object Date] { ... },
    //   name: "test.png",
    //   size: 3860,
    //   slice: function slice() { [native code] },
    //   type: "image/png",
    //   webkitRelativePath: ""
    // }]
}

JSBin Demo

更多關於Blob, Buffer的知識個人也還在學習當中
希望本篇內容對大家有所幫助,如有錯誤歡迎糾正指導。

參考資料


上一篇
DAY 29. JavaScript Canvas 處理
系列文
重新學習網頁設計30

尚未有邦友留言

立即登入留言