EPUB 檔案格式
EPUB 電子書——一個裝著 XHTML 內容與資源清單的 ZIP 壓縮檔。
- MIME 類型
- application/epub+zip
- 副檔名
- .epub
- 分類
- 文件
Magic number(檔案簽章)
| 0x00000000 | 504B0304 | PK·· | 'PK' — it is a ZIP |
ZIP 內含一個 'mimetype' 項目,內容為 'application/epub+zip'。
關於 EPUB 格式
EPUB 是開放的電子書標準,結構上就是塞在 ZIP 裡的一個網站:可重排的 XHTML 文件、CSS、字型與圖片,加上一份列出所有資源與閱讀順序的套件文件。和其他所有以 ZIP 為基礎的格式不同,EPUB 的容器規格把壓縮檔開頭那幾個位元組釘得死死的,所以它是少數能光靠標頭辨識、不必看目錄清單的容器格式。這是刻意的設計,為的是讓伺服器或偵測器不用解壓縮就認得出型別。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 4 | Local file header signature | 50 4B 03 04。EPUB 就是普通的 ZIP 壓縮檔;底下這些都是它第一個項目的 ZIP 本地檔案標頭,只是 OCF 規格對這些欄位的約束比 ZIP 本身嚴格得多。 |
| 4 | 2 | Version needed to extract | 0A 00,也就是 10,因為第一個項目必須是直接儲存而不是 deflate,而直接儲存的項目只需要 1.0 版。這裡看到 14 00 代表寫入端把 mimetype 項目壓縮了,這個套件已經不符規格。 |
| 6 | 2 | General purpose bit flag | 00 00。mimetype 項目不得使用 data descriptor,所以位元 3 是 0,底下的 CRC 與大小都是真實數值而不是零。整個標頭之所以能是確定的,關鍵就在這裡。 |
| 8 | 2 | Compression method | 00 00——直接儲存、未壓縮。規格明文要求,用意正是讓媒體型別字串以可讀 ASCII 出現在檔案的固定位置,而不是躲在 deflate 資料流裡。 |
| 10 | 2 | Last modified time | MS-DOS 打包的時間。這是規格唯一放任不管的欄位,所以它會隨檔案不同而變,周圍的東西則不會。 |
| 12 | 2 | Last modified date | MS-DOS 打包的日期,年份從 1980 起算。OCF 同樣沒有約束,資訊量同樣是零——這本書真正的日期在套件文件的中繼資料裡。 |
| 14 | 4 | CRC-32 | 6F 61 AB 2C,也就是小端序的 0x2CAB616F,每一個符合規格的 EPUB 都是這個值——因為項目內容是固定的,檢查碼自然是常數。這裡出現別的值,代表 mimetype 檔的內容不是預期的那 20 個位元組。 |
| 18 | 4 | Compressed size | 14 00 00 00,20 個位元組。因為項目是直接儲存,所以和未壓縮大小相等。 |
| 22 | 4 | Uncompressed size | 14 00 00 00,也就是 20——字串 application/epub+zip 的位元組長度,結尾不能有換行。這裡多一個換行的檔案會驗證失敗,而原因在文字編輯器裡完全看不出來。 |
| 26 | 2 | File name length | 08 00,8 個位元組,對應名稱 'mimetype'。規格釘死的,要求就是這個全小寫的 ASCII 名稱。 |
| 28 | 2 | Extra field length | 00 00。規格禁止這個項目帶額外欄位,這正是媒體型別字串保證落在位移 38、而不是更後面某處的原因。 |
| 30 | 8 | Entry name | ASCII 的 'mimetype'。它必須是壓縮檔的第一個項目,所以前面不能有任何其他檔案。 |
| 38 | 20 | Media type string | 字面的 ASCII application/epub+zip。要讓它出現在這裡,得同時滿足六個獨立條件——直接儲存、沒有額外欄位、沒有 data descriptor、名稱一字不差、長度一字不差、排在壓縮檔第一位——這讓位移 38 那 20 個位元組成為比位移 0 的 'PK' 強得多的識別依據。 |
| variable | variable | META-INF/container.xml | 第二個必備項目,不過它不在固定位移。它是讀取端唯一事先知道位置的檔案,存在的唯一目的就是指向套件文件——通常是 OEBPS/content.opf——套件文件再列出 manifest 與 spine,也就是資源清單與有序的閱讀順序。 |
| -22 | 4 | End of central directory signature | 50 4B 05 06,在沒有壓縮檔註解時位於倒數第 22 個位元組。就算開頭釘得再死,EPUB 仍然是 ZIP:讀取端是從檔尾的中央目錄列舉資源的,所以被截斷的檔案打不開,即使它前 58 個位元組完美無瑕。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| ZIP | 每個 EPUB 都是 ZIP,但幾乎沒有 ZIP 是 EPUB。這個測試強度異常地高,因為 OCF 把整個第一項目都釘死了:位移 8 是方法 0、位移 26 名稱長度是 8、位移 28 額外欄位長度是 0、位移 30 是 'mimetype'、位移 38 是 application/epub+zip,加上位移 14 的常數 CRC 0x2CAB616F。一般用途的壓縮檔不可能六項全中。 |
| Word 文件(docx) | 兩者都是裝 XML 的 ZIP 套件,也都會讓只看到 'PK' 就收工的粗糙偵測器翻車。OOXML 在位元組層級什麼都沒釘,靠的是套件根目錄出現 [Content_Types].xml——通常在位移 30;EPUB 則把整個第一項目都釘死。位移 30 讀到 'mimetype' 就是 EPUB,讀到 '[Content_Types].xml' 就是 OOXML。 |
| MOBI/AZW | 亞馬遜較早的電子書格式,而且根本不是 ZIP:那是從 PalmDOC 衍生出來的容器,位移 60 有 ASCII 字串 'BOOKMOBI';KF8/AZW3 則是包著同一個容器。Kindle 裝置讀的是那些,而且直到相對近期都完全不讀 EPUB,所以同一本書常常兩種格式都發。 |
| 兩種電子書交付格式,設計上正好相反。PDF 把每個字元釘在固定頁面的座標上;EPUB 是會依螢幕與讀者選的字級重排的 XHTML。這就是為什麼「到哪都要長一樣」的文件該用 PDF、而 PDF 在手機上很糟,EPUB 則反過來。 |
常見的壞法
- mimetype 項目被壓縮或被移位。弄壞 EPUB 最常見的方式,就是用普通的 zip 指令重新打包,它會把每個項目都 deflate,還可能重排順序。結果是一個完全合法的 ZIP,而閱讀器拒收,因為媒體型別字串不再是位移 38 的明碼 ASCII。要正確打包,得先把 mimetype 以不壓縮的方式加進去,其他東西再跟上。
- 壓縮檔尾巴不見了。前 58 個位元組把檔案身分交代得漂漂亮亮,書還是打不開,因為閱讀器是從檔尾的中央目錄列舉資源的。從 50 4B 03 04 往後切出各項目、重建目錄,XHTML 能完整救回。
- META-INF/container.xml 不存在,或它指向的套件文件不在。壓縮檔裡其他東西可以完好無缺——章節、圖片、樣式表——閱讀器卻找不到入口,於是整本書看起來是空的。這是指標壞掉而不是資料壞掉,手動就修得回來。
- manifest 和壓縮檔內容對不起來。每個資源都必須在套件文件裡宣告;ZIP 裡有、manifest 裡沒有的章節,就是永遠不會出現,而 manifest 裡有、卻找不到對應檔案的項目,會讓嚴格的閱讀器整本書都拒收。這兩種在任何 ZIP 工具眼裡都不算損壞。
- 文字模式傳輸。換行轉換讓每個固定標頭欄位照樣讀得出來——mimetype 是直接儲存的,所以它真的活得下來——同時悄悄破壞各章節的 deflate 資料流。書被正確辨識、也打得開,然後讀到一半 CRC 不符。
這個格式現在還在用嗎
除了亞馬遜的生態系之外,EPUB 就是各處的電子書標準:圖書館外借的是它、出版社交付的是它、Apple Books、Kobo、Google Play Books 和每個開源閱讀器吃的都是它,而 2022 年起 Kindle 的個人文件也收它了。第 3 版讓它更貼近它本來就依附的網頁技術——HTML5、CSS3、內嵌字型、MathML、可跟讀的媒體疊加音訊,以及足以做互動教科書的指令碼能力。它的定義性特質是重排:文字會順應任何螢幕尺寸與讀者選的字級,這正是手機上讀小說需要的,也正是 PDF 做不到的。同一個特質也讓它不適合任何「版面本身帶有意義」的東西——有精確圖表的技術書、樂譜、漫畫和送印稿還是走 PDF,而 EPUB 的固定版面設定檔比較像是權宜之計,不算它的強項。把 EPUB 當一般 ZIP 對待之前,有一件事要先知道:用普通的 zip 指令重新打包會把它弄壞,因為第一個項目的儲存方式是寫在規格裡的,不是實作細節。
在這個站上打開 EPUB 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 EPUB 搞混的格式,可以比對它們的開頭位元組。
| 格式 | 開頭位元組 | 副檔名 |
|---|---|---|
| ZIP | 50 4B 03 04 | .zip |
| Word 文件(docx) | 50 4B 03 04 | .docx |
| HTML | 無固定簽章 | .html |