我有几个带文件的文件夹,有些文件夹的名字中包含非拉丁符号(在我的情况下是俄语)。此文件夹正在“D:\ test.zip”中发送到zip存档(由Windows资源管理器)。 然后我执行method
ZipFile.ExtractToDirectory(@"D:\test.zip", @"D:\result");
它成功解压缩了所有内容,但所有非拉丁符号都变成了错误。
例如,代替“D:\ result \каскады\ file.txt”我得到“D:\ result \ЄбЄ¤л\ file.txt”。
我的系统的默认编码是 windows-1251 ,我通过将Encoding.GetEncoding("windows-1251")
纳入ExtractToDirectory
的第三个参数并获得相同的结果来验证。我也试过 UTF-8 ,但在路径中有另外的文物(“D:\ result \ ᪠ \ file.txt”)。尝试 Unicode 会返回有关不支持编码的消息。
当我通过代码执行method
创建相同的存档时 ZipFile.CreateFromDirectory(@"D:\zipdata", @"D:\test.zip");
然后,即使没有指定特定的编码,也可以使用与问题顶部相同的代码行解压缩。
问题是:如何从档案中获取正确的编码,以便在ExtractToDirectory
方法中应用它,因为在实际任务档案中来自外部来源,我不能依赖于“手工”或编程?
修改
还有question非拉丁符号(中文)也会引起问题,但这个问题就像解决问题一样,而这对我的情况来说确实是个问题。
答案 0 :(得分:5)
没有正式标准化的ZIP规范。但是,事实上的标准是the PKZIP "application note" document,截至2006年,只有代码页437(“OEM美国”)和UTF8作为档案中文件条目的法律文本编码:
D.1 ZIP格式历来只支持原始的IBM PC角色 编码集,通常称为IBM代码页437.这限制了存储 文件名字符仅限于原始MS-DOS值范围内的字符 并且不能正确支持其他字符编码中的文件名,或 语言。为了解决这个限制,本规范将支持 以下变化。
D.2如果未设置通用位11,则文件名和注释应符合 到原始的ZIP字符编码。如果设置了通用位11,则 文件名和注释必须支持Unicode标准版本4.1.0或 使用UTF-8存储定义的字符编码格式更大 规格。 Unicode标准由The Unicode发布 联盟(www.unicode.org)。存储在ZIP文件中的UTF-8编码数据 预计不包括字节顺序标记(BOM)。
换句话说,任何ZIP创作工具中的错误都是使用除代码页437或UTF8之外的任何文本编码。根据您的经验,Windows Explorer出现此错误。 :(
不幸的是,“通用位11”是用于指示存档中使用的实际文本编码的唯一官方机制,并且这仅允许原始437代码页或UTF8。甚至这一点was not supported by .NET until .NET 4.5。在任何情况下,即使从那时起,.NET或任何其他ZIP存档感知软件都无法可靠地确定用于对存档中的文件条目名称进行编码的非标准,不受支持的编码。
但是,可以,如果用于创建存档的源计算机已知且可用,则通过CultureInfo
类确定该计算机上安装的默认代码页。以下表达式将返回安装在执行表达式的机器上的代码页标识符(假设该进程当前未将其当前区域性更改为默认值):
System.Globalization.CultureInfo.CurrentCulture.TextInfo.OEMCodePage
这为您提供了代码页ID,可以传递给Encoding.GetEncoding(Int32)
以检索Encoding
对象,然后在打开现有存档时将其传递给相应的ZipArchive
构造函数,确保正确解码文件条目名称。
如果您无法从作为存档原点的计算机中检索实际文本编码,那么您将无法枚举编码,尝试每个编码,直到找到以清晰易读的格式报告条目名称的编码。
据我了解,Windows 8及更高版本可以支持ZIP存档文件中的UTF8标志。我没有尝试过,但是这样的Windows版本也可能使用该标志写档案。如果是这样,那将(人们希望)减轻早期Windows错误的痛苦。
最后请注意,自定义工具可以将编码记录在存档本身中的特殊文件条目中。当然,只有该工具才能识别特殊文件并使用它来确定正确的编码(该工具必须打开存档两次:一次检索文件,然后一旦工具确定了编码)。这不是一个理想的解决方案,当然对Windows资源管理器创建的档案没有帮助。我只是为了完整而提到它。