使用ExtractToDirectory方法解压缩会扭曲非拉丁符号

本文关键字:丁符号 符号 方法 ExtractToDirectory 解压缩 使用 | 更新日期: 2023-09-27 18:11:26

我有几个文件夹,其中一些文件夹的名称中包含非拉丁符号(我的情况是俄语)。此文件夹将发送到"D:'test.zip"中的zip存档(通过windows资源管理器)。然后执行方法

    ZipFile.ExtractToDirectory(@"D:'test.zip", @"D:'result");

,它成功地解压缩了所有内容,但所有非拉丁符号都变成了错误。

例如,

而不是 " D: ' 'каскады' file.txt " " D: ' 'ЄбЄ¤л' file.txt "

我的系统的默认编码是windows-1251,我通过将Encoding.GetEncoding("windows-1251")纳入ExtractToDirectory的第三个参数来验证,得到了相同的结果。我还尝试了UTF-8,但在路径内得到了另一个工件("D:'result'᪠'file.txt")。尝试Unicode返回关于不支持编码的消息。

当我通过执行方法

创建相同的存档时
    ZipFile.CreateFromDirectory(@"D:'zipdata", @"D:'test.zip");

所有内容都可以解压缩,即使没有指定特定的编码方式,也可以使用与问题顶部相同的代码行。

问题是:如何从存档中获得正确的编码,以便在ExtractToDirectory方法中应用它,就实际任务存档来自外部来源而言,我不能依赖于它是"手工"还是编程创建的?

编辑
有一个问题,非拉丁符号(中文)也会引起问题,但这个事实就像问题的解决一样,而这正是我的情况的问题。

使用ExtractToDirectory方法解压缩会扭曲非拉丁符号

没有正式标准化的ZIP规范。然而,事实上的标准是PKZIP"应用说明"文档,截至2006年,该文档仅将代码页437("OEM United States")和UTF8作为存档中文件条目的合法文本编码:

D.1ZIP格式历来只支持原始IBM PC字符编码集,通常称为IBM代码页437。这限制了存储将文件名字符改为仅在原始MS-DOS值范围内的字符并且不能正确支持其他字符编码的文件名,或者语言。为了解决这个限制,本规范将支持后改变。

D.2如果通用位11未设置,则文件名和注释应符合到原来的ZIP字符编码。如果设置了通用位11,则文件名和注释必须支持Unicode标准版本4.1.0或使用由UTF-8存储定义的字符编码形式更大规范。统一码标准由统一码协会发布财团(www.unicode.org)。存储在ZIP文件中的UTF-8编码数据期望不包含字节顺序标记(BOM)。

换句话说,使用代码页437或UTF8以外的任何文本编码都是任何ZIP创作工具中的错误。根据你的经验,Windows资源管理器似乎有这个bug。(

不幸的是,"通用位11"是唯一的官方机制,用于指示存档中使用的实际文本编码,这只允许原始437代码页或UTF8。直到。net 4.5才支持这一点。在任何情况下,即使从那时起,. net或任何其他ZIP存档感知软件也不可能可靠地确定用于对存档中的文件条目名称进行编码的非标准、不支持的编码。

但是,如果用于创建存档的源机器已知且可用,则可以通过CultureInfo类确定安装在该机器上的默认代码页。下面的表达式将返回安装在执行表达式的机器上的代码页标识符(当然,假设进程没有从默认设置更改其当前区域性):

System.Globalization.CultureInfo.CurrentCulture.TextInfo.OEMCodePage 

这为您提供了可以传递给Encoding.GetEncoding(Int32)以检索Encoding对象的代码页ID,然后可以在打开现有存档时传递给适当的ZipArchive构造函数,以确保文件条目名称被正确解码。


如果您无法从作为存档源的机器中检索实际的文本编码,那么您就会陷入枚举编码的困境,尝试每一种编码,直到找到一种以清晰格式报告条目名称的编码。

据我所知,Windows 8及以后版本可以在ZIP存档文件中支持UTF8标志。我还没有试过,但这类版本的Windows也可能使用该标志来写存档。如果是这样的话,这将(人们希望)减轻早期Windows错误带来的痛苦。


最后请注意,自定义工具可以将编码记录在放置在存档本身中的特殊文件条目中。当然,只有该工具能够识别特殊文件并使用它来确定正确的编码(该工具必须打开存档两次:一次检索文件,然后在工具确定编码后再打开第二次)。这不是一个理想的解决方案,当然对Windows资源管理器创建的档案没有帮助。我提到它只是为了完整。