ByteScope

RTF 檔案格式

Rich Text Format,一種跨平台的格式化文字文件格式。

MIME 類型
application/rtf
副檔名
.rtf
分類
文件

Magic number(檔案簽章)

0x000000007B5C72746631{\rtf1'{\rtf1' header

關於 RTF 格式

RTF 整份文件都是可列印的 ASCII:大括號開關群組,反斜線開頭的控制字帶著格式資訊,其餘就是字面文字。這讓它成為唯一一種你可以在文字編輯器裡直接讀、直接 diff、直接修好的文書處理格式,也是唯一一種被貼進郵件軟體還活得下來的格式。代價是體積和保真度——含圖片的 RTF 大得誇張,因為每張圖的每個位元組都得寫成十六進位數字。

檔頭結構,一個位元組一個位元組看

位移長度欄位意義
01Opening group brace位元組 7B,也就是 '{'。整份文件是一個群組,所以這個大括號的配對對象就是檔案的最後一個位元組。群組會巢狀,而括號沒配對是 RTF 檔壞掉最常見的單一原因。
14\rtf control word4 個位元組 5C 72 74 66。控制字是一個反斜線接小寫字母,後面可帶一個數值參數;這一個指名格式本身,而且必須是最外層群組裡的第一個東西。
51Version digit\rtf 的數值參數,而且所有發行過的 RTF 這裡都是單一個 ASCII 字元 '1'。規格都走到 1.9.1 了,這個數字從來沒有加過,所以它標示的是格式而不是版本。
6variableCharacter set control word規格要求字元集必須緊接在版本後面。你幾乎永遠只會看到 \ansi,佔 5 個位元組;\mac、\pc、\pca 是舊的替代選項,長度較短,會讓底下每個位移往前移。
11variable\ansicpg code page只有在字元集控制字是 5 個位元組的 \ansi 時,才剛好落在這個位移。它的參數是文件內容所使用的 Windows 字碼頁——1252 是西歐、936 是簡體中文、932 是日文。超出該字碼頁的字元會改用 \'hh 或 \uNNNN? 逸出。
variablevariable\deff, \fonttbl and \colortbl字碼頁後面接的是預設字型索引,然後是字型表群組 {\fonttbl ...},通常還有一個色彩表 {\colortbl ...}。它們的位移取決於上面所有東西,但它們一定是群組、一定在文件本文之前,所以把前面幾百個位元組 dump 出來,就能看到明碼 ASCII 的字型名稱。
-11Closing group brace位元組 7D,也就是 '}',關掉位移 0 開的那個群組。有些寫入端會在後面補一組 CR LF。如果最後一個非空白位元組不是右大括號,這個檔案就是被截斷了——而且和多數格式不同,你常常可以自己手動把缺的括號補回去修好它。

怎麼跟長得像的格式分開

容易搞混的怎麼分
Word 文件(docx)位元組層級一點都不像——'{\rtf1' 對上 50 4B 03 04——但一般人講「不是 .doc 的 Word 檔」時,指的就是這兩種。Word 兩種都讀也都寫,而且 .docx 改名成 .rtf 照樣在 Word 裡打得開,因為 Word 是看位元組的。RTF 不帶修訂歷程、不帶註解討論串、也不能內嵌字型,所以「另存成 RTF」是一種刻意把文件剝乾淨的手法。
OLE2 / CFB這一對才是真的會搞混,因為 '.doc' 最後可能是這兩種的任一種。真正的 Word 97 二進位文件是 Compound File Binary 容器,開頭 D0 CF 11 E0;但以 .doc 散布出去的檔案裡,有非常多其實是 RTF,因為 RTF 到哪都打得開,而那個副檔名大家比較熟。看位移 0,不要看副檔名:'{\rtf1' 沒有模稜兩可的空間。
HTML兩者都是由可讀 ASCII 組成的標記語言,也都是你複製格式化文字時剪貼簿會提供的東西——Windows 會同時放上 RTF 和 HTML。位移 0 一眼就分得出來,但實務上真正的差別是 RTF 完全沒有外部參照:沒有連結的樣式表、沒有遠端圖片,全部都是內嵌的,這也是為什麼陌生人寄來的檔案,收 RTF 比收 HTML 安全。
純文字(帶 BOM 的 UTF-8)RTF 嚴格說來就是純 ASCII 文字,所以只檢查「位元組是否可列印」的粗糙偵測器會把它判成純文字——而文字編輯器也真的打得開,只是會把標記全攤在你面前。分辨的方法是開頭那 6 個位元組;另外要注意 RTF 不允許帶 UTF-8 BOM,因為檔案必須以大括號起頭,所以位移 0 出現 EF BB BF 就代表這個檔案被動過手腳。

常見的壞法

  • 大括號沒配對。因為群組會巢狀、控制字會從外層群組繼承,少一個 '}' 就等於那個群組裡設定的每一項格式全部漏到文件剩下的部分。看得到的症狀是:檔案打得開,後半段字型不對或整段變粗體,而且從頭到尾沒有任何錯誤訊息。
  • 字碼頁設錯。\ansicpg 寫 1252,但內容其實是用 936 寫的話,每個非 ASCII 字元都會變亂碼。檔案一個位元組都沒壞、文件結構也完好無缺——錯的只是位移 11 那一個數字,把它改對,整份文件就復原了。
  • 被截斷。被切掉的 RTF 在多數文書軟體裡照樣打得開,它們就把解析到的部分算繪出來,然後自己把沒關的群組收掉。這種寬容是個陷阱:文件看起來很完整,最後幾頁卻無聲無息地不見了。檢查最後一個非空白位元組是不是 '}'。
  • 字面文字裡有沒逸出的反斜線。特殊字元只有反斜線、大括號和那幾種逸出序列,所以寫入端忘了逸出一個字面的 '\' 或 '{',就會把使用者的文字變成控制字。結果是那段文字從算繪結果裡消失,但在 hex dump 裡看得一清二楚。
  • 換行字元轉換,這次難得無害。RTF 會忽略控制字以外的 CR 與 LF,所以那個會毀掉 PNG 或 ZIP 的文字模式傳輸,對 RTF 完全沒影響。它是極少數真的能撐過 ASCII 模式 FTP 的準二進位格式。

這個格式現在還在用嗎

RTF 是備援格式,而且到現在還是最好用的那個備援。沒有人會選它來寫東西,但「給我一份有格式、到哪都打得開的檔案」的可靠答案還是它,因為 1987 年之後寫出來的每一套文書軟體都讀得懂,而且都不用外掛。它特別活躍在三個地方:Windows 和 macOS 剪貼簿的格式化文字類型,所以應用程式之間每一次帶樣式的複製貼上,本質上都走了一趟 RTF;不能綁定單一廠商的法務與政府系統的匯出格式;以及來路不明文件的安全收件格式,因為 RTF 沒有巨集、沒有指令碼、也沒有外部參照。微軟在 2008 年的 1.9.1 版之後就停止開發規格,Word 自己的 RTF 轉換器也已經標為淘汰,所以它是被凍住而不是還在演進。要做新東西,.docx 保真度高得多、體積只有零頭——放了幾張照片的 RTF 動輒幾十 MB,因為圖片是以 ASCII 十六進位存的,體積先翻倍,而且完全沒有壓縮。

在這個站上打開 RTF 檔

這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。

相關格式

容易和 RTF 搞混的格式,可以比對它們的開頭位元組。

格式開頭位元組副檔名
Word 文件(docx)50 4B 03 04.docx
OLE2 / CFBD0 CF 11 E0 A1 B1.doc
PDF25 50 44 46 2D.pdf

常見問題

檔案的 magic number 是什麼?

檔案開頭的前幾個位元組,不管檔名寫什麼,它標明的是真正的格式。PNG 一定以 89 50 4E 47 開頭,ZIP 則是 50 4B 03 04。作業系統、瀏覽器和 file 指令讀的都是這幾個位元組,而不是相信副檔名 — 這就是為什麼把檔案改名並不會改變它實際上是什麼。

我要怎麼自己檢查 magic number?

在 macOS 或 Linux 上,xxd -l 16 檔名 會印出前 16 個位元組;在 Windows 上,PowerShell 的 Format-Hex -Path 檔名 -Count 16。或者把檔案丟進本站的檔案類型辨識工具,它會在本機讀取位元組並告訴你是什麼格式,不會上傳任何東西。

為什麼兩種格式的 magic number 會一樣?

因為其中一種是建立在另一種之上。docx、xlsx、pptx、apk、jar 與 epub 骨子裡都是 ZIP 壓縮檔,所以全都以 ZIP 的簽章開頭;要分辨它們得看裡面的項目。Java class 檔和 macOS 的通用二進位檔都以 CA FE BA BE 開頭,靠緊接其後的欄位區分。

有完全沒有 magic number 的檔案嗎?

有。XML、HTML、JSON、SVG、CSV 這類以文字為基礎的格式沒有固定的位元組簽章,所以改用結構來辨識:開頭的 <?xml 宣告、<svg 元素,或是 { 後面接著帶引號的鍵。這種偵測是合理推測而非確定,因此本參考頁會把這些格式標示為結構偵測。

magic number 相符就代表檔案安全嗎?

不代表。它告訴你的是格式,不是內容是否無害 — 一個貨真價實的 PDF 或 docx 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

手上有檔案可能是 RTF?用檔案類型辨識工具查出來 — 它在本機讀取 magic number,不上傳任何東西。或者瀏覽所有格式。