從 0/1 到 0-255 — 理解 Byte 的誕生
如果你曾經好奇:「Blob 明明是二進制資料,只有 0 和 1,為什麼討論時又會冒出 0-255 這個範圍?」
這個問題觸及了計算機科學中 「編碼 (Encoding)」 與 「資料單位」 的核心觀念。
簡單的答案是:0 和 1 實在太小了,電腦為了方便管理,把每 8 個 0/1 打包成一組,這一組就叫做「Byte (位元組)」。而這一組所能表示的數字範圍,剛好就是 0 到 255。
一、 從 Bit 到 Byte:打包的藝術
電腦底層確實只有 Bit (位元),也就是開關(0 或 1)。但如果我們傳輸資料只講 0 和 1,效率會極低且人類無法理解。
TIP
比喻 就像你去便利商店買米,你不會跟店員說:「我要 50,000 粒米」,你會說:「我要 1 包 米」。
在電腦世界裡,「1 包」的標準規格就是 8 粒米 (8 Bits)。這包米就叫做 Byte (位元組)。
單位定義
| 單位 | 定義 | 範圍 |
|---|---|---|
| 1 Bit | 1 個開關 | 0 或 1 |
| 1 Byte | 8 個 Bits 排在一起 | 0 ~ 255 |
二、 數學解密:為什麼是 255?
當我們把 8 個開關排成一列,會有多少種組合?
每個位置都有 2 種可能(0 或 1),總共有 8 個位置:
$$ 2^8 = 256 \text{ 種狀態} $$
這代表一組 Byte 可以組出 256 種狀態。如果用十進位數字來表示:
- 最小的狀態 (全都是 0):
00000000= 0 - 最大的狀態 (全都是 1):
11111111= 255
二進位轉十進位計算
二進位的 11111111 換算成十進位是這樣加的:
位置: 7 6 5 4 3 2 1 0
權重: 128 64 32 16 8 4 2 1
值: 1 1 1 1 1 1 1 1
總和 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255所以,0 到 255 是一個 Byte 用無符號整數表示時的數值範圍。電腦當然可以做 bit 層級操作,但在檔案、網路與 Web API 的實務中,我們最常以 Byte 為基本單位讀寫資料。
三、 Blob 與 0-255 的關係
回到主題:Blob 是一大塊二進制資料。
雖然它的本質是長長一串的 010101...,但在程式語言(JavaScript, Python, C++)眼中,它被視為一個 「由 0-255 數字組成的超長陣列」。
舉個例子:一張圖片的 Blob
假設你有一個很小的紅色像素點圖片,它在 Blob 裡的樣子可能長這樣(簡化版):
| 記憶體位置 | 二進位 (電腦看的) | 十進位 (程式碼看的) | 意義 |
|---|---|---|---|
| Byte 1 | 11111111 | 255 | 紅色 (R) |
| Byte 2 | 00000000 | 0 | 綠色 (G) |
| Byte 3 | 00000000 | 0 | 藍色 (B) |
| Byte 4 | 11111111 | 255 | 透明度 (Alpha) |
這就是為什麼你在 CSS 設定顏色時會看到 rgb(255, 0, 0)。在常見的 8-bit RGB/RGBA 表示法裡,每個色彩通道會用一個 Byte (0-255) 表示強度。
四、 在 JavaScript 中親眼看到它
在 Web 開發中,Blob 通常是包起來的,你看不到內容。但如果你把它「切開」變成 ArrayBuffer,再用 Uint8Array 去讀取,就會看到滿滿的 0-255。
Uint8Array 名詞解釋
- Unsigned: 無符號(沒有負數,只有正數)
- Int: 整數
- 8: 8 位元 (8 bits)
- Array: 陣列
翻譯: 「由 8 個 bit 組成的正整數陣列」,也就是 0-255 的陣列。
實際操作範例
你可以試著在瀏覽器的 Console 跑這段程式碼:
// 1. 建立一個簡單的 Blob (裡面只有文字 "Hi")
const blob = new Blob(["Hi"]);
// 2. 把 Blob 轉成 ArrayBuffer (取得記憶體控制權)
blob.arrayBuffer().then((buffer) => {
// 3. 用 "8位元視角" 去看這塊記憶體
const view = new Uint8Array(buffer);
console.log(view);
// 輸出: Uint8Array(2) [72, 105]
// 為什麼是 72 和 105?
// 因為在 UTF-8/ASCII 中,英文字母 H 和 i 都各佔 1 byte:
// 'H' = 72
// 'i' = 105
// 這些數字都在 0-255 之間!
});TypedArray 家族
除了 Uint8Array,JavaScript 還提供其他「視角」:
| 類型 | 每個元素大小 | 數值範圍 | 用途 |
|---|---|---|---|
Uint8Array | 1 Byte | 0 ~ 255 | 處理原始二進位、圖片像素 |
Uint16Array | 2 Bytes | 0 ~ 65535 | 音訊採樣 |
Uint32Array | 4 Bytes | 0 ~ 4,294,967,295 | 大整數運算 |
Float32Array | 4 Bytes | 浮點數 | WebGL 頂點座標 |
如果你把 Blob 換成中文,例如 new Blob(["你好"]),Uint8Array 會看到 6 個數字,因為 UTF-8 會用 3 bytes 表示一個常見中文字。這也是為什麼「文字長度」和「檔案 byte 數」經常不是同一件事。
五、 為什麼這很重要?
理解了 Blob 其實就是一堆 0-255 的數字後,你就能做到:
- 初步檔案驗證:透過檢查檔案開頭的數字(Magic Numbers),比副檔名更可靠地判斷檔案類型
- 檔案修復:有些損壞的檔案只是多了幾個錯誤的 Byte,你可以直接修正
- 自定義格式:你甚至可以發明自己的檔案格式,例如前 4 個 Byte 存版本號,後 4 個 Byte 存作者 ID
常見誤解
| 誤解 | 正確理解 |
|---|---|
| 二進位資料只能看成 0 和 1 | 底層是 bit,但程式通常用 byte 或 typed array 來看 |
| 1 個字元等於 1 byte | 只對部分編碼與字元成立,UTF-8 中文通常不是 |
Uint8Array 會複製 Blob | 它是用 8-bit 視角讀取 ArrayBuffer,不是直接操作原本的 Blob |
| 0-255 是所有整數的限制 | 這只是 1 byte 無符號整數的範圍 |
總結
| 概念 | 說明 |
|---|---|
| Bit | 最小單位,0 或 1,太細微難以操作 |
| Byte | 8 個 Bit 綁成一組,數值範圍 0-255 |
| Blob | 成千上萬個 Byte 堆疊起來的大物體 |
| Uint8Array | 用 0-255 視角去讀取二進制資料的工具 |
當我們說 Blob 是二進制資料時,意思是它底層是 0/1;但當我們去「讀取」或「處理」它時,我們是把它當成一連串 0-255 的數字在看。
練習:猜 byte 數
練習 1:英文和中文差在哪?
先猜 byteLength 分別是多少:
const a = new Blob(["Hi"]);
const b = new Blob(["你"]);
const c = new Blob(["你好"]);
console.log((await a.arrayBuffer()).byteLength);
console.log((await b.arrayBuffer()).byteLength);
console.log((await c.arrayBuffer()).byteLength);看答案
在 UTF-8 中,"Hi" 是 2 bytes,"你" 通常是 3 bytes,"你好" 通常是 6 bytes。這能驗證「字元數」不等於「byte 數」。
練習 2:親手看見 0-255
const blob = new Blob(["ABC"]);
const bytes = new Uint8Array(await blob.arrayBuffer());
console.log([...bytes]);你應該會看到 [65, 66, 67]。接著把 "ABC" 改成 "abc",觀察數字如何變化。
自我檢查
- 為什麼 1 byte 的最大值是 255,不是 256?
Uint8Array的每個元素可以放300嗎?- 為什麼中文字的 byte 數通常比字元數多?
- Blob 底層是 bit,但為什麼程式常用 byte 來看?