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

我有几个文件夹,一些文件夹的名称中包含非拉丁符号(在我的情况下是俄语)。 此文件夹正在“D:\ test.zip”中发送到zip存档(由Windows资源管理器)。 然后我执行方法

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

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

例如,我得到了“D:\ result \ЄбЄ¤л\ file.txt”而不是“D:\ result \ каскады\ file.txt”

我的系统的默认编码是windows-1251 ,我通过将Encoding.GetEncoding("windows-1251")纳入ExtractToDirectory第三个参数并获得相同的结果来validation。 我也试过UTF-8 ,但在路径中有另外的文物( “D:\ result \ ᪠ \ file.txt” )。 尝试使用Unicode返回有关不支持编码的消息。

当我通过执行方法通过代码创建相同的存档时

  ZipFile.CreateFromDirectory(@"D:\zipdata", @"D:\test.zip"); 

然后,即使没有指定特定的编码,也可以使用与问题顶部相同的代码行解压缩。

问题是:如何从存档中获取正确的编码以便在ExtractToDirectory方法中应用它,因为在实际任务存档中来自外部源并且我不能依赖于它“通过手”或编程创建的位置?

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

没有正式标准化的ZIP规范。 但是,事实上的标准是PKZIP“应用说明”文档 ,该文档截至2006年仅将代码页437(“OEM美国”)和UTF8文档编码为存档中文件条目的法律文本编码:

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

D.2如果未设置通用位11,则文件名和注释应符合原始ZIP字符编码。 如果设置了通用位11,则文件名和注释必须使用UTF-8存储规范定义的字符编码格式支持Unicode标准版本4.1.0或更高版本。 Unicode标准由The Unicode Consortium(www.unicode.org)发布。 存储在ZIP文件中的UTF-8编码数据预计不包括字节顺序标记(BOM)。

换句话说,任何ZIP创作工具中的错误都是使用除代码页437或UTF8之外的任何文本编码。 根据您的经验,Windows Explorer出现此错误。 🙁

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

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

 System.Globalization.CultureInfo.CurrentCulture.TextInfo.OEMCodePage 

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

如果您无法从作为存档原点的计算机中检索实际文本编码,那么您将无法枚举编码,尝试每个编码,直到找到以清晰易读的格式报告条目名称的编码。

据我了解,Windows 8及更高版本可以支持ZIP存档文件中的UTF8标志。 我没有尝试过,但是这样的Windows版本也可能使用该标志写入档案。 如果是这样,那将(人们希望)减轻早期Windows bug的痛苦。

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