zip 文件中西里尔文文件名的编码

zip 文件中西里尔文文件名的编码

这里有一些关于 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 {} \;

或者转化率公用事业。

答案1

我在 OpenNET.ru 论坛上找到了一个解决方案,这是一个流行的俄语资源,自 1996 年以来一直致力于开源软件和技术。在 OpenNET 上发布Info-ZIP 曾经是一套在运行 MS-DOS 的计算机上处​​理 ZIP 档案的流行工具,它认为在 MS-DOS 上只有一种 8 位编码,即 CP850,因此所有文件名都会自动通过CP850->CP1252转换运行。 CP1252 可能被选为最流行的 ISO-8859-1 字符集编码近似值。

因此,在提取包含西里尔文文件名的存档后运行的正确查找命令是

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:是一种保护措施,可以隐藏存档名称以防止转换。

答案2

与“最近”infozip 一起使用的 ZIP 文件显示正确的文件名:

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

РосКосмос/并且 unzip在解压时 正确创建目录。

infozip 很久以前就添加了 UTF-8 支持。我的 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)

这似乎与编译/构建选项有关

答案3

zip 的这个问题已经固定的在最近的far2l 文件和存档管理器。为了让 far2l 的 zip 旧字符集检测正常工作,您的系统语言设置应该与创建存档的系统上设置的语言设置相匹配(Windows 的内部“zip 文件夹”工具使用相同的逻辑)。你也可以做

LANG=ru_RU.UTF-8 far2l

答案4

OEM 代码页选择在 vanilla unzip 和 vanilla p7zip 中均被破坏。我制造了一个修补解决这个问题并且有适用于 Ubuntu 的 ppa使用应用了此补丁的 p7zip。

相关内容