移至主內容
DarkRanger's Secret Area

主導覽

  • 首頁
  • 關於本站
  • Linux
  • 程式開發
  • N900
  • 譯文
  • 資訊技術辭典

文章分類

  • 影劇
  • 遊戲
  • 筆記
  • 雜文
  • 資訊技術
  • 站務訊息

最新內容

  • How-To:Linux 安裝 DevilutionX
  • 於 2012 年建立的一份音樂播放清單
  • How-To:Linux 安裝 Medal of Honor: Allied Assault
  • Fallout 4 (2015)
  • How-To:Linux 安裝 Blood
  • 《終極動員令》系列早期作品原始碼釋出
  • How-To:Linux 安裝 Doom 3
  • Nausicaä of the Valley of the Wind (1984)
  • Intel 內顯與 Linux 桌面死當問題排解
  • 《哥吉拉 -1.0》心得補遺

Python 讀取 Big5 編碼的 ZIP 壓縮檔

發表日期:星期六, 10/15/2022 - 17:43,更新日期:星期日, 10/16/2022 - 15:25

很難預想到,即便在 2022 年的現代作業系統中,仍然會遇到與古老 Big5 編碼有關的問題。然而就 Windows 來說確實是如此,時至今日為止,至少在隨處可見的 Windows 10 繁中環境裡,其預設的環境編碼依然是 CP950(微軟自行維護的 Big5 實作)。因此根據壓縮軟體的具體實作而異,所生產出來的 ZIP 壓縮檔,寫入的檔名清單不盡然都會是 Unicode,也有可能依然是 CP950。

 

延伸閱讀:libarchive 函式庫關於檔名處理的說明文件。

 

話說好段時間前 DR 曾因工作環境需要,寫了一支 Python 程式,用於讀取 *.zip、*.rar 及 *.7z 這幾種常見壓縮檔中的檔案清單,藉此對上傳附件的正確性做某種程度的檢查。其中針對 ZIP 的讀取,除了 Unicode 無須特別處理外,也是有考量到 CP950 的編碼。所以程式碼裡會嘗試對 ZipFile.infolist() 所回傳的物件清單,執行以下的檔名解碼動作:

filename.encode("cp437").decode("cp950)

 

起初似乎都運作正常,直到某日出現無法正確解碼的錯誤(illegal multibyte sequence)。於是將問題檔名列出來一看,赫然驚覺難不成是遇到了 Big5「許蓋功」的問題?在進一步的查看下,確實發覺 filename 背後的位元組不太正常,應該是十六進位值 5C 的地方,都變成了 2F。舉例來說,中文字「許」在 Big5 編碼裡應該是 B35C,但在 filename 裡面的值卻是 B32F,導致解碼失敗。

 

然而當下也搞不清楚這是怎麼發生的,而且其它 Windows 下的壓縮軟體也都能夠正常開啟該壓縮檔。於是索性先將解碼動作修改如下,程式能跑最重要:

filename.replace("\x2F", "\x5C").encode("cp437").decode("cp950)

 

直到最近比較有空之後,才想說回頭來看看究竟是怎麼回事。然而一開始的調查方向有點偏差,是聚焦在壓縮軟體處理檔名的過程,但翻找軟體的原始碼並未看出什麼特別的跡象。後來在 Linux 下測試時,發現相同的 Python 程式碼讀取同一個壓縮檔,並未出現如 Windows 那樣,數值異常以致解碼錯誤的情形,才發覺應該是在 Python 裡面發生了什麼奇怪的事情。

 

原來在 Python 的 zipfile 模組裡,會找尋 filename 裡面的路徑分隔符號(os.sep),並統一為正斜線「/」。由於 Windows 下的 os.sep 為反斜線「\」,因此就形成了「\」( 5C)皆被替換為「/」(2F)的情形。反之在 Linux(或者 WSL)下就不會有此情形,也就不會出現錯誤。

 

所以在使用 zipfile 模組來讀取 ZIP 壓縮檔時,更加直觀且相對健全的 Big5 檔名應對方式應是像這樣:

filename.replace("/", "\\").encode("cp437").decode("cp950").replace("\\", "/")

 

zip_encoding_test.py 是一支用於驗證前述情形的 Python 程式。程式碼雖有些繁雜,但基本功能很單純。倘若在 Windows 下執行時,它會執行 tar 指令,產生一個內含「許蓋功」的 test.zip。接著讀取該壓縮檔,分別列出 ZipInfo 物件中 orig_filename 及 filename 的十六進位值,藉此檢視 filename 屬性在 Windows 環境下所發生的變化。

 

筆記