在 TypeScript 中將檔案轉換為 Base64,其依據來自 RFC 4648 的一條規則:每三個原始位元組會成為標準字母表中的四個可列印 ASCII 字元;當最後一組只有一個或兩個位元組時,則以一個或兩個結尾的等號補齊。在瀏覽器中,你不需要 Node 執行環境、遠端 API 或第三方 SDK 就能正確遵循此規則。瀏覽器的 File API 會以 ArrayBuffer 的形式提供所選檔案的精確位元組,而一小段 TypeScript 程式碼就能將該緩衝區編碼為正規且帶有填補的 Base64,或將嚴格的 Base64 字串解碼回使用者可儲存的 Blob。問題在於,像 btoa 這類內建輔助函式只接受字串、無法處理 0x7F 以上的位元組,而且在解碼端也不會強制執行正規的填補,因此任何需要對任意二進位資料進行往返處理的正式工作流程,都必須正確地對緩衝區進行分塊,或將工作交給已經實作 RFC 4648 規則的工具。這個工具就是 File to Base64 Converter,它會讀取你目前分頁中的檔案,並回傳可以直接貼入 TypeScript、JSON 或請求主體的正規帶填補輸出。

為何 TypeScript 無法解決編碼問題
TypeScript 在 JavaScript 之上加入了靜態型別,但底層的字串與二進位基本型別並未改變。圍繞著 btoa 撰寫的型別化封裝仍然會拒絕任何 0xFF 以上的位元組,並且在非 Latin1 輸入時拋出例外。大多數開發者第一次嘗試的直覺作法,是將整個 Uint8Array 用擴展運算子展開成 String.fromCharCode,但對於大約 110 KB 以上的檔案,擴展運算子會拋出 RangeError,因為呼叫堆疊無法容納數十萬個引數。解法是以固定大小的區塊來處理緩衝區,每塊最多 0x8000 位元組,再將編碼結果串接起來。在 TypeScript 中,一段簡短且防禦性的編碼器看起來像這樣:
const CHUNK = 0x8000; export function encodeRFC4648(bytes: Uint8Array): string { let binary = ''; for (let i = 0; i < bytes.length; i += CHUNK) { const slice = bytes.subarray(i, i + CHUNK); binary += String.fromCharCode.apply(null, slice as unknown as number[]); } return btoa(binary); }
這個迴圈會產生帶有等號填補的標準 Base64,但它在解碼端並未強制使用嚴格的 RFC 4648 字母表,也不會拒絕非正規的填補位元。為了往返處理的安全性,特別是在 Base64 內容跨越 JSON 酬載、設定檔或 curl 命令時,你會需要一套只輸出一種正規形式並拒絕其他所有拼法的工作流程。防止瀏覽器堆疊溢出的同一套邏輯,正是像 Base64 Decode Bulk Pastes Without Stack Overflow 這類文章建議以固定切片處理、而非一次產出巨大字串的原因。
使用瀏覽器工具在 TypeScript 中將檔案轉換為 Base64
當你不想自己部署編碼與解碼程式時,File to Base64 Converter 會替你完成正規的 RFC 4648 處理,並將位元組保留在當前分頁內。無論目的地是 TypeScript 模組、Postman 環境,還是手寫的 fetch 主體,流程都相同。
- 在你撰寫 TypeScript 程式碼的分頁中開啟 File to Base64 Converter。
- 點擊檔案選擇器,選擇任意大小不超過 10 MB 的本機檔案。該工具透過瀏覽器 File API 讀取精確的位元組,而非字串解讀。
- 等待正規且帶填補的 Base64 字串出現在輸出區域。確認檔案名稱與大小與你選擇的一致。
- 複製整個輸出。該字串僅包含 Base64 字元與結尾的等號;沒有 data URL 前綴、沒有 MIME 標頭、沒有換行,也沒有嵌入的檔名。
- 將該字串以字串字面值、JSON 欄位或 fetch 請求主體的形式貼入你的 TypeScript 原始碼,並以與來源檔案相同的機密程度來對待編碼後的內容。
每一步都在本機執行。位元組不會被上傳,且當你替換轉換內容或關閉頁面時,暫時性的 Blob URL 會被撤銷,避免正常使用下累積過時的下載連結。
使用 TypeScript File API 讀取精確的位元組
如果你偏好在自己的元件中進行編碼,File API 會直接提供你所需的原始位元組,無需經過 base64 的間接處理。一個最簡單的讀取器看起來像這樣:
const picker = document.querySelector('#picker') as HTMLInputElement; picker.addEventListener('change', async () => { const file = picker.files && picker.files[0]; if (!file) return; const buffer = await file.arrayBuffer(); const bytes = new Uint8Array(buffer); const encoded = encodeRFC4648(bytes); console.log(encoded.length, encoded); });
由於 arrayBuffer 會回傳檔案的精確位元組序列,編碼器會保留每一個位元組,包括零值以及 0x7F 以上的位元組。編碼器不會轉碼影像、不會正規化換行符號,也不會去除中繼資料;它只負責將位元組表示為文字。若檔案小到你想要用一行解決,FileReader.readAsArrayBuffer 會回傳相同類型的緩衝區,而 FileReader.readAsDataURL 則會回傳以 data: 開頭,加上 MIME 類型與字面前綴 base64, 的 data URL 字串;這個前綴屬於 data URL 規範的一部分,而非 RFC 4648 Base64 的一部分,嚴格的解碼器會拒絕它。
陷阱:Data URL、填補與 URL 安全字母表
TypeScript 開發者第一次將檔案透過 Base64 處理時,常會遇到以下三個陷阱:
- Data URL 前綴。以 data:image/png;base64, 開頭的字串,在實際酬載之前包含了 MIME 類型與字面符記 base64,。期望正規 RFC 4648 內容的伺服器與嚴格解碼器會拒絕整個字串。請在管線中一個明確的位置去除前綴,千萬不要在解碼中途處理。
- 省略或多餘的填補。某些程式庫輸出的 Base64 沒有結尾的等號。RFC 4648 規定必須有填補,嚴格的解碼器會拒絕較短的版本。請在帶填補與不帶填補的設定檔之間明確轉換,而非憑猜測處理。
- Base64url。JWT、網址縮短服務以及少數網路 API 會使用 URL 安全字母表,其中加號變為減號、斜線變為底線。該字母表與正規 Base64 無法互通;請先將其轉回標準形式再進行解碼。
如果你將帶有空格、換行、data URL 前綴或 URL 安全字元的字串貼入 File to Base64 Converter 的解碼輸入框,解碼器會拒絕它。這樣的行為是刻意的:唯有嚴格的輸入,才能保證損壞的位元組永遠不會進入 Blob。
在 TypeScript 中將 Base64 解碼為可下載的檔案
當目的地預期得到 File 或 Blob 時,你可以反過來處理流程。瀏覽器內建了 atob,用以解碼標準 Base64,並提供了 Blob 加上 URL.createObjectURL 來產生暫時性的下載連結:
const canonical = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; const binary = atob(canonical); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i); const blob = new Blob([bytes], { type: 'image/png' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'pixel.png'; a.click(); URL.revokeObjectURL(url);
atob 並不會驗證正規的填補位元,也會接受某些非正規的拼法。因此,對於從外部 API 接收 Base64 輸入的正式程式碼,請將輸入送往一個會重新編碼位元組並拒絕不符結果的嚴格解碼器。File to Base64 Converter 正是這樣做的:它會透過一個獨立的編碼步驟往返處理輸入、比對結果與預期向量,凡是不符者一律拒絕,然後在你目前的瀏覽器工作階段範圍內建立暫時性的 Blob URL。所選擇的檔名決定下載時的建議名稱,MIME 欄位決定 Blob 的媒體類型;這兩個欄位都不會更動位元組本身。
何時該使用工具而非自行撰寫
| 考量面向 | 在 File API 上自行以 TypeScript 實作 | File to Base64 Converter |
|---|---|---|
| 位元組的處理位置 | 保留在瀏覽器中,但你必須自行強制執行填補與正規字母表。 | 保留在當前分頁內;編碼與解碼皆為本機作業。 |
| 嚴格解碼 | atob 會接受某些非正規的拼法。 | 解碼後重新編碼,並拒絕非正規的輸入。 |
| 記憶體上限 | 受限於你程式碼的分塊策略。 | 在設計上限定為 10,000,000 位元組。 |
| 輸出形式 | 由你選擇:帶填補、不帶填補或 data URL。 | 永遠是正規且帶填補的 RFC 4648。 |
| 檔名與 MIME | 由你自行建立 Blob 與中繼資料。 | 由你設定檔名與 MIME 欄位;工具負責建立 Blob URL。 |
若檔案超過 10 MB,請改用串流式的命令列工具,例如 Linux 上的 base64,或 .NET 管線中的 Convert.ToBase64String;瀏覽器分頁並不適合處理 GB 等級的酬載。10 MB 的上限是為了保護分頁的記憶體,因為位元組陣列、Base64 字串與呈現的輸出會在轉換期間同時存在,過大的檔案會讓這個組合超出一般瀏覽器工作階段的承受範圍。
在往返處理之後驗證位元組
正規的 Base64 只能證明字母表與填補正確,無法證明位元組本身具有任何意義。在解碼回檔案之後,請在擁有該格式的應用程式中開啟結果。若需要確保完整性,請以 SHA-256 雜湊來源檔案,並與解碼後檔案的雜湊進行比對。若兩個雜湊不同,表示位元組的遺失發生在 Base64 步驟之外,因為 Base64 本身是一種無損且可逆的編碼,會保留每一個輸入位元組,包括零值與 0x7F 以上的位元組。編碼器從不檢查或重寫檔案格式、不會正規化換行、不會轉碼影像,也不會解讀中繼資料;因此,通過 RFC 4648 的往返處理只代表一件事:輸出的位元組等同於輸入的位元組。
Putting the TypeScript Workflow Together
A clean TypeScript workflow for file-to-Base64 has three stages. First, read the file with the File API through arrayBuffer so you receive the exact bytes, not a string interpretation. Second, encode those bytes into canonical padded RFC 4648 Base64, either in your own chunked code or through the File to Base64 Converter. Third, hand the string to whatever consumes it, a JSON payload, a fetch body, a curl command, or a config file, and keep the destination's expected profile in mind. When you need the reverse direction, paste canonical Base64 into the same tool, set a real filename and a MIME type that matches the file's actual format, decode, and download the temporary Blob. Throughout the round-trip, remember that Base64 is encoding, not encryption: anyone with the string can decode it, so treat the encoded output with the same sensitivity as the source file and avoid pasting it into logs, tickets, or analytics where the original bytes would not belong.
Related reading: AES Encryption Online API Alternative: Browser-Side.