Character-Encoding

zip 文件中西里爾文文件名的編碼

  • October 11, 2020

這裡有一些關於在 zip 文件(希伯來語中文日語或韓語)中儲存為流的文件名稱中的非 ASCII 字母的問題。但是,所提供的解決方案都沒有幫助我處理來自 Windows 機器的帶有西里爾字母的 zip 文件。

該文件本身有一個西里爾字母名稱(Космос.zip - 可下載連結)。這是一個零長度內容的存檔,僅用於說明目的。

unzip -l印刷:

Archive:  Космос.zip
 Length      Date    Time    Name
---------  ---------- -----   ----
       0  2017-05-03 18:19   ɫ���߼��/ict_inf.pdf
---------                     -------
       0                     1 file

醜陋的ɫ���߼��代表字節序列C9 AB DF E8 AB DF BC AB DF

我知道(通過使用 GMail 預覽功能)這應該是

Archive:  Космос.zip
 Length      Date    Time    Name
---------  ---------- -----   ----
       0  2017-05-03 18:19   РосКосмос/ict_inf.pdf
---------                     -------
       0                     1 file

那就是我們需要映射C9 AB DF E8 AB DF BC AB DFРосКосмос.

有幾種常用的 8 位西里爾編碼:CP1251、CP866、ISO8859-5,但是它們會將這個字編碼為不同的字節序列:

          Р  о  с  К  о  с  м  о  с
CP866:     90 AE E1 8A AE E1 AC AE E1
CP1251:    D0 EE F1 CA EE F1 EC EE F1
ISO8859-5: C0 DE E1 BA DE E1 DC DE E1

顯然,沒有一個常用的 8 位西里爾編碼會像這樣將輸入名稱解碼為輸出名稱。這裡有更複雜的工作。

如果我們知道如何解碼名稱,使用適當的find腳本(https://unix.stackexchange.com/a/252000/17649)可以輕鬆地在提取後重命名文件,例如

find -mindepth 1 -exec sh -c 'mv "$1" "$(echo "$1" | here-goes-the-decoding pipeline )"' sh {} \;

convmv實用程序。

與“最近”資訊壓縮一起使用的 ZIP 文件顯示正確的文件名:

unzip -l Russian-Космос.zip 
Archive:  Russian-Космос.zip
 Length      Date    Time    Name
---------  ---------- -----   ----
       0  2017-05-03 18:19   РосКосмос/ict_inf.pdf
---------                     -------
       0                     1 file

解壓時解壓正確創建РосКосмос/目錄。

UTF-8 支持已被添加到 infozip 很久以前。我的 Ubuntu 上的執行檔:

UnZip 6.00, 20 April 2009
Zip 3.0,  July 5th 2008

所以你的問題可能是一個古老的 InfoZip 版本(或者一個沒有 UTF-8 支持的編譯版本)

在我的版本中strings /usr/bin/unzip | grep -A8 -B8 'UTF-8',除其他外,產量:

ZIP64_SUPPORT (archives using Zip64 for large files supported)
LARGE_FILE_SUPPORT (large files over 2 GiB supported)
other
UTF-8
UNICODE_SUPPORT [wide-chars, char coding: %s] (handle UTF-8 paths)
USE_DEFLATE64 (PKZIP 4.x Deflate64(tm) supported)
USE_UNSHRINK (PKZIP/Zip 1.x unshrinking method supported)

這似乎與編譯/建構選項有關

我在 OpenNET.ru 論壇上找到了一個解決方案,這是一個流行的俄語資源,自 1996 年以來一直致力於開源軟體和技術。OpenNET 上的一篇文章表明 Info-ZIP,曾經是處理 ZIP 的流行工具集執行 MS-DOS 的電腦上的檔案假定在 MS-DOS 上只有一種 8 位編碼,即 CP850,因此所有文件名都會自動通過CP850->CP1252轉換執行。CP1252 可能被選為最流行的 ISO-8859-1 字元集編碼近似值。

因此,在提取包含西里爾文文件名的存檔後執行的正確 find 命令將是

find -mindepth 1 -exec sh -c 'mv "$1" "$(echo "$1" | iconv -f cp1252 -t cp850 | iconv -f cp866 )"' sh {} \;

有趣的是,可以找到不使用 CP1252 而是使用 ISO-8859-1 的建議。情況似乎並非如此,因為我遇到的一些檔案在成功轉換iconv -f iso8859-1 -t cp850時失敗了iconv -f cp1252 -t cp850

回到單個角色

          Р  о  с  К  о  с  м  о  с
CP866:     90 AE E1 8A AE E1 AC AE E1

現在應用 CP850 -> CP1252 結果在C9 AB DF E8 AB DF BC AB DF. 正是我們觀察到的序列。

另一個有用的命令是

unzip -l РосКосмос.zip | grep -aEv '^Archive:' | iconv -f iso8859-1 -t cp850 | iconv -f cp866

從存檔中獲取文件列表

Length      Date    Time    Name
---------  ---------- -----   ----
       0  2017-05-03 18:19   РосКосмос/ict_inf.pdf
---------                     -------
       0                     1 file

過濾掉以開頭的行Archive:是一種保護,以隱藏存檔名稱以防止轉換。

引用自:https://unix.stackexchange.com/questions/362812