理解 Unix 文件名編碼
我很難理解文件名編碼是如何工作的。在 unix.SE 上,我發現了相互矛盾的解釋。
文件名儲存為字元
引用另一個答案: 關於 linux 上的文件系統字元編碼的幾個問題
$$ … $$正如您在問題中提到的,UNIX 文件名只是一個字元序列;核心對編碼一無所知,這完全是一個使用者空間(即應用程序級)的概念。
如果文件名儲存為字元,則必須涉及某種編碼,因為最終文件名必須以磁碟上的位或字節序列結尾。如果使用者可以選擇任何編碼將字元映射到饋送到核心的字節序列,則可以為有效文件名創建任何字節序列。
假設如下:使用者使用隨機編碼X,將文件
foo
轉換為字節序列α並將其保存到磁碟。另一個使用者使用編碼Y。在這種編碼中, α轉換為/
,不允許作為文件名。但是,對於第一個使用者,該文件是有效的。我認為這種情況不會發生。
文件名儲存為二進制 blob
引用另一個答案: Linux 上的文件名和路徑使用什麼字元集編碼?
正如其他人所指出的,對此並沒有真正的答案:文件名和路徑沒有編碼;作業系統只處理字節序列。個別應用程序可能會選擇將它們解釋為以某種方式編碼,但這會有所不同。
如果系統不處理字元,如何在文件名中禁止特定字元(例如
/
或)? 沒有編碼NULL
就沒有 a 的概念。/
一種解釋是文件系統可以儲存包含任何 字元的文件名,並且只有將編碼考慮在內的使用者程序才會阻塞包含無效字元的文件名。反過來,這意味著文件系統和核心可以毫無困難地處理包含
/
.我也認為這是錯誤的。
編碼發生在哪里以及不允許特定字元的限制在哪裡?
namei()
簡短回答:在 Unix/Linux/BSD 核心、功能中施加的限制。編碼發生在使用者級程序中,例如xterm
,firefox
或ls
.我認為您是從不正確的前提開始的。Unix 中的文件名是具有任意值的字節串。一些值,0x0 (ASCII Nul) 和 0x2f (ASCII ‘/’) 是不允許的,不能作為多字節字元編碼的一部分,不能作為任何東西。一個“字節”可以包含一個表示字元的數字(在 ASCII 和一些其他編碼中),但一個“字元”可能需要超過 1 個字節(例如,Unicode 的 UTF-8 表示中高於 0x7f 的程式碼點)。
這些限制來自文件名列印約定和 ASCII 字元集。最初的 Unix 使用 ASCII ‘/’(數字為 0x2f)值字節來分隔部分或完全限定路徑的片段(如 ‘/usr/bin/cat’ 有片段 “usr”、“bin” 和 “cat”) . 最初的 Unix 使用 ASCII Nul 來終止字元串。除了這兩個值之外,文件名中的字節可以採用任何其他值。您可以在 Unicode 的 UTF-8 編碼中看到它的迴聲。可列印的 ASCII 字元,包括“/”,在 UTF-8 中只佔用一個字節。上述程式碼點的 UTF-8 不包括任何零值字節,Nul 控製字元除外。UTF-8 是為 Plan-9 發明的,即 Unix 王座的偽裝者。
較舊的 Unix(它看起來像 Linux)有一個
namei()
函式,它一次只查看一個字節的路徑,並將路徑分成 0x2F 值字節的片段,在零值字節處停止。namei()
是 Unix/Linux/BSD 核心的一部分,因此這是強制執行異常字節值的地方。請注意,到目前為止,我討論的是字節值,而不是字元。
namei()
不對字節強制執行任何字元語義。這取決於使用者級程序,例如ls
,它可能根據字節值或字元值對文件名進行排序。xterm
根據字元編碼決定為文件名點亮哪些像素。如果你不告訴xterm
你有 UTF-8 編碼的文件名,當你呼叫它時你會看到很多亂碼。如果vim
沒有編譯為檢測 UTF-8(或其他,UTF-16、UTF-32)編碼,當您打開包含 UTF-8 編碼字元的“文本文件”時,您會看到很多亂碼。