在 Windows 下面處理 Unicode 檔名問題

昨天在 PTT 看到一個問題關於讀取 Unicode 檔案名稱的問題…

作者 danny0838 (道可道非常道) 看板 PHP
標題 [請益] Windows 上的中文檔案
時間 Thu Mar 25 00:59:32 2010
──────────────────────────────────────

因為某些因素,小的有用 php 存取 windows 系統上中文檔名檔案的需求..

我知道繁中版 windows 的檔名是用 big5 編碼,
假設一個檔案名為 “測試.txt”,而 php 程式是 UTF-8 編碼,
用 iconv(“UTF-8″,”big5//IGNORE”,”測試.txt”) 即可讀到該檔案。

但如果檔名包含 unicode 呢?
比如 “消化酶.txt”(酉每是 unicode 字元),它會被編為什麼碼?

第二個問題是,若用 scandir 之類的方式掃資料夾,
純 big5 檔名會以 big5 格式傳回,可做進一步應用;
但夾有 unicode 的檔案傳回值一部分會變成 ? (UTF-8 無法對應到 big5 者),
造成路徑錯誤,掃到檔案卻無法進一步處理。

所以,要如何用 php 存取 windows 系統下,檔名夾有 unicode 字元的檔案呢?

先講解答,答案是沒辦法,但如果是用 Linux + Unicode 檔名,同樣的條件則是完全沒問題。

可以寫一段簡單的測試程式來驗證

執行結果:

Noname

但執行環境如果換到 Window 下面的話,一樣的程式碼,則會帶來不同的結果:


Noname

實際開啟檔案,裡面的「酶」被換成了「?」這個字元,這是因為 PHP 在 Windows 讀檔名的時候,沒辦法讀出 Unicode 字元。因為 PHP 在 Windows 對 Unicode 支援並不完整。如果用 .NET Framework (原生 Unucode) 就不會有這樣的問題了。我寫了一個簡單的程式來測試,原始碼如下:

  • 開一個新目錄,然後建立一個檔案叫做「消化酶.txt」
  • 用上面這隻程式讀取目錄下所有檔案,並且顯示內容
  • 雖然在畫面上一樣顯示不出來「酶」這個字,是因為在 Console 顯示不出 CP950 以外的字,但可以確定 C# 操作的 resource 底層可以正確存取這個檔案物件。
  • 驗證方法是把取回的檔名轉成 Unicode (UTF-16) ,然後以 HEX 碼印出,再對照實際檔名字串(以 Unicode 編碼)的 HEX Code 這樣就可以確定沒錯了。


Noname

(連結可以開原圖)

所以說,用 PHP 要讀取 Windows 含有 Unicode 字元的檔案,目前是有困難。

Posted in 碎碎念
2 comments on “在 Windows 下面處理 Unicode 檔名問題
  1. jeffhung says:

    既然 C# 沒問題,那就不該是「Windows 自己的相容性都做不好。」若底層 OS 做不好,上層的應用程式開發工具又怎有辦法解決?MBCS 版 API 因為要向前相容而仍然使用 CP950,「酶」這個字的確是無解了。但我確定 Unicode 版 API 沒問題,可以用 Unicode 檔名(UCS2-LE)。問題應該這麼說,是 PHP 的 win32 版有問題,沒用 Unicode 版 win32 API 實作,當然匯出問題。

Leave a Reply

Your email address will not be published.