在 JavaScript 中將檔案轉換為 Base64,代表透過瀏覽器的 File API 讀取 File 物件的精確位元組序列,並輸出符合 RFC 4648 的標準表示法,整個過程完全不將位元組上傳到遠端伺服器。JavaScript 在瀏覽器分頁內執行,所以轉換可以在本地完成:從選定的檔案取得 arrayBuffer,再送入一個將每三個位元組群組轉為四個標準字母字元,並在剩餘位元組不足時以等號填補的例程。內建的輔助函式如 btoa() 與 atob() 僅接受 Latin-1 字串,這代表任何包含 0x7F 以上位元組的任意二進位檔案,都需要一個能感知位元組的處理流程,而非直接呼叫 btoa。因此,實際的工作流程是讀取檔案、以 24-bit 為單位逐一處理位元組,並寫入 A–Z、a–z、0–9、+、/,最後再用等號完成任何殘留的部分群組。輸出結果是純文字,目的端系統可以將其解碼回原始位元組,過程中不會遺失、不會進行編碼轉換,也不會重寫中繼資料。

由於轉換過程都停留在分頁內部,JavaScript 開發者可以將編碼器掛接到點擊處理常式、將輸出貼到另一個應用程式,或與原始碼一同存放,完全不需要接觸網路。工作流程中嚴格的一面與編碼器同樣關鍵:當目的端交給你一段 Base64 字串要解碼回檔案時,JavaScript 端必須拒絕空白字元、要求標準填補,並在產生位元組之前拒絕非零的未使用填補位元數。本文後續將逐步說明讀取檔案的步驟、本地工具的做法、規範正確輸出時所依循的 RFC 4648 確切規則,以及在手寫編碼器與解碼器時會出現的各種陷阱。

convert file to base64 in javascript
在 JavaScript 中將檔案轉換為 Base64:在本地執行

JavaScript 如何以原始位元組讀取檔案

現代瀏覽器透過 <input type="file"> 或拖放區域公開 File 物件(Blob 的子類別)。若要在 JavaScript 中對該檔案進行編碼,你需要的是精確的位元組序列,而非字串解讀。常見的兩種路徑是 FileReader 與較新的 Blob.arrayBuffer() Promise,兩者差異在於回傳的內容。

作法讀取對象輸出格式是否能處理任意二進位備註
FileReader.readAsArrayBufferFile 或 Blob原始 ArrayBuffer可以事件驅動;舊版 API,但仍廣泛支援
blob.arrayBuffer()File 或 Blob以 Promise 形式回傳原始 ArrayBuffer可以適合 async/await;建議在新程式碼中使用
FileReader.readAsDataURLFile 或 Blobdata:<mime>;base64,... 字串可以,但輸出會包進 data URL 前綴方便用於圖片預覽;若要產生標準輸出需去除前綴
FileReader.readAsBinaryStringFile 或 Blob依 Latin-1 解讀的字串有限;每個位元組會對應到一個碼點規格中已棄用;不建議用於任意二進位
btoa(stringFromFile)僅限字串輸入Latin-1 位元組的 Base64否——遇到 ≥ 0x80 的位元組會拋出例外無法直接對真正的二進位檔案編碼

瀏覽器的 File API 是讓 JavaScript 頁面透過 arrayBuffer 讀取選定檔案、且完全不離開分頁的基礎,這也是 File to Base64 Converter 在本地處理時所依賴的相同界線。W3C File API 規範說明了使用者代理程式如何向腳本公開 File,以及如何透過 Blob 介面讀取其位元組。

為什麼嚴格的本地工具對 JavaScript 編碼很有用

手寫一個 JavaScript 編碼器是個有價值的練習,但實際的工作流程必須每次都正確:字母表必須是 RFC 4648 標準字元(+ 與 /,而非 URL-safe 變體)、最後一個群組若只剩一個或兩個位元組就必須出現等號、輸出不能插入換行,而且從 0x00 到 0xFF 的位元組必須逐字保留。一個本地瀏覽器工具可以透過對自身輸出與標準 RFC 向量進行比對來鎖定這些規則——空輸入、f、fo、foo、foob、fooba、foobar,再加上會用到這兩個字元的負載。File to Base64 Converter 採用的正是這份契約:透過 File API 讀取位元組、以標準字母表編碼、套用必要的填補,並且絕不轉碼、標準化換行符號、或重寫中繼資料。

同樣的嚴格要求也適用於反向作業。一個默默接受空白字元、丟棄填補、或忽略非零填補位元的 JavaScript 解碼器,有時會回傳原始位元組,有時會回傳一個微妙不同的位元組序列——這是最糟的失敗模式,因為問題只會在目的端才顯現出來。一個嚴格的解碼器會驗證字母表、要求正確數量的等號,並將解碼後的位元組重新編碼以拒絕非標準的替代拼寫。由於此轉換器所產生的暫時 Blob URL 會在下次轉換取代時被撤銷,因此也能避免在多次編碼/解碼循環中累積過時的下載連結。

在 JavaScript 中將檔案轉換為 Base64:逐步說明

本逐步操作使用本地工具,從你選擇的磁碟檔案產生符合 RFC 4648 的標準輸出,接著再將同一段字串反轉為可下載的檔案。兩個方向都停留在當前分頁內執行。

  1. 在瀏覽器中開啟 File to Base64 Converter,並確認目的端應用程式需要的是標準帶填補的 Base64(不是 Base64url、沒有 MIME 換行、沒有 data: 前綴)。
  2. 從磁碟中選擇檔案。此工具接受最大 10,000,000 位元組的檔案,這限制了單一分頁內可同時存在的記憶體 ArrayBuffer、Base64 字串與渲染輸出大小。
  3. 確認頁面所顯示的檔名與大小,然後複製完整的標準帶填補輸出。複製的文字只會包含 Base64 字元與等號——不含 MIME 標頭、不含 data URL 前綴,也沒有任何換行。
  4. 將 Base64 字串依原樣貼入目的端應用程式。若目標需要包裝格式,請僅依其規格進行包裝,切勿自行猜測。
  5. 若要反轉方向,請將工具切換到 Base64-to-file 模式,並貼上不含空白字元、不缺填補、且無非零填補位元的標準 Base64。
  6. 設定符合實際檔案格式的正確檔名與 MIME 類型。這兩個欄位會影響下載建議與 Blob 媒體類型;它們不會檢查或修改解碼後的位元組。
  7. 點擊 decode 以建立暫時下載,接著用平常開啟此檔案的應用程式(或在需要確保完整性時使用加密雜湊)來驗證所得到的檔案格式與完整性。

「標準」輸出對你的 JavaScript 程式碼代表什麼

兩段 Base64 字串即使解碼後得到相同的位元組,若其中一個是由非標準編碼器產生,兩者在字元層級仍可能不同。RFC 4648 規定了固定規則:字母表為 A–Z、a–z、0–9、+、/,當最後一個群組只剩一個或兩個位元組時以等號填補,最後一個量子內未使用的位元必須為零。RFC 中的七個測試向量分別為 "" → ""、"f" → "Zg=="、"fo" → "Zm8="、"foo" → "Zm9v"、"foob" → "Zm9vYg=="、"fooba" → "Zm9vYmE="、"foobar" → "Zm9vYmFy"。無法重現全部七個向量的 JavaScript 編碼器即代表有誤。

外觀相似但實際上並非標準的格式包含 Base64url(會將 + 與 / 換成 - 與 _,且通常省略填補)、MIME 包裝的 Base64(每 76 個字元插入一個換行符號),以及 data: URL(會前置 MIME 類型與字面文字 base64,)。期待上述其中一種格式的目的端將無法接受標準帶填補的輸出,反之亦然;因此本轉換器的編碼器僅輸出標準形式,並將格式轉換交由呼叫端處理。相同的紀律也出現在專門用於產生標準 RFC 4648 輸出,以及將轉換保留在本地瀏覽器分頁中的專題指南中。

嚴格解碼:JavaScript 端必須產生什麼

解碼是多數 JavaScript 流程默默出錯的地方,因為寬鬆的行為會讓格式錯誤的輸入通過。嚴格的規則很簡短:每個字元都必須來自標準字母表、輸入不得包含任何空白字元、最後一個群組必須帶有正確數量的等號(零、一或兩個),且最後一個量子內未使用的填補位元必須全部為零。填補位元的規則很容易被忽略,因為許多程式庫仍會照常解碼,且問題只在目的端才會顯現——最後一個位元組內僅僅一個位元的差異就會產生不同的輸出值。

因此,一個嚴格的解碼器會將剛解碼得到的位元組重新編碼,並將結果與原始輸入進行比對,藉此拒絕替代拼寫而非默默接受。負面測試案例(包含空白字元、缺少填補、非零填補位元)能確保寬鬆的瀏覽器行為無法掩蓋格式錯誤的輸入。解碼器也必須一開始就拒絕其他變體格式:Base64url、MIME 包裝的輸出與 data: URL 必須在解碼前,經由明確步驟轉換為標準帶填補的 Base64,絕不能仰賴寬鬆的回退機制。若 JavaScript 程式碼接收到上述任一種容器,請先依該格式自身的規則移除包裝,再將標準內容送入嚴格解碼器。

在 JavaScript 中對檔案進行編碼的常見陷阱

只要 JavaScript 開發者手動對檔案編碼,總會反覆出現一些錯誤。第一個是在由檔案構成的字串上呼叫 btoa():btoa 僅接受 Latin-1 碼點,因此任何高於 0x7F 的位元組(這佔了大多數的二進位內容)都會拋出 InvalidCharacterError。正確做法是透過能處理二進位的例程來編碼 ArrayBuffer 的位元組,而非透過字串轉換。第二個錯誤是將 FileReader.readAsBinaryString 視為二進位 API;此方法已被棄用,會將每個位元組視為碼點,這會將高位元組折疊為模糊的 Latin-1 字元,在某些編碼下會遺失資訊。

另一個陷阱是過度包裝。將 data: URL 貼入期待純 Base64 的系統將會失敗,反之,將純 Base64 貼入期待 data: URL 的系統也會失敗。請讓輸出格式與目的端明確要求的格式一致。編碼也會讓負載增加大約三分之一,因為三個輸入位元組會變成四個輸出字元;當字串被儲存於記錄檔、票據、原始檔或分析資料中時,這點就會變得重要——可辨識的內容可能出現在原本不該存放檔案位元組的地方。最後,請記住解碼器所建議的檔名與 MIME 類型僅是中繼資料;誤導性的副檔名或媒體類型可能會混淆其他應用程式,因此應依你對檔案格式的瞭解來填寫,而非依 Base64 字串的表面樣式來推測。

When to Reach for a Tool Instead of Writing It Yourself

Hand-written JavaScript is the right choice for embedding an encoder inside a component, a build step, or a service worker where you control every line. A strict local tool is the right choice when you want canonical RFC 4648 output verified against the published test vectors, when you need a strict decoder that rejects malformed input, or when you simply need the round-trip to work without writing the binary-to-Base64 routine from scratch. Either way, keep three rules in mind: the conversion should stay on the device that holds the bytes, the output must use the standard alphabet with required padding, and the destination format must match what the consumer expects. With those rules in place, "convert a file to Base64 in JavaScript" stops being a guessing game and becomes a deterministic, reproducible operation that you can plug into any pipeline.

If you're weighing options, Gzcompress Online on iPhone: Run It in Safari covers this in detail.

If you're weighing options, HMAC Generator Bulk: Compute Many HMAC Tags Locally covers this in detail.