代码之家  ›  专栏  ›  技术社区  ›  Martin M

zip中文件的编码(C#/ionic zip)

  •  5
  • Martin M  · 技术社区  · 6 年前

    zip文件中的文件编码有问题。 我们正在使用ionic zip压缩和解压缩档案。 我们位于丹麦,所以我们经常有包含或在文件名中的文件。

    当用户使用windows内置工具压缩文件时,我发现它使用的是IBM437编码,当我们有包含“”/“”的文件时,这只会产生一些奇怪的结果。我用以下代码修复了此问题:

    public static string IBM437Encode(this string text)
    {
        return text.Replace('ø', '¢').Replace('Ø', '¥');
    }
    public static string IBM437Decode(this string text)
    {
        return text.Replace('¢', 'ø').Replace('¥', 'Ø');
    }
    

    这已经运行了一段时间了,一切都很好。

    但是,因为总是有一个But,我们没有使用mac osx中的默认工具对文件进行压缩。 所以现在我们有了一个新问题。。 使用æ、Ã184;和Ã¥时,编码为UTF-8! 因此,如果我知道zip压缩的位置,我就可以让它工作,但是有没有简单的方法来检测或规范zip中的编码?

    1 回复  |  直到 6 年前
        1
  •  6
  •   Nyerguds    6 年前

    检测编码总是一件棘手的事情,但是UTF8 has strict bitwise rules about what values are expected in a valid sequence ,并且可以初始化UTF8Encoding对象 in a way that will fail by throwing an exception when these sequences are incorrect :

    public static Boolean MatchesUtf8Encoding(Byte[] bytes)
    {
        UTF8Encoding enc = new UTF8Encoding(false, true);
        try { enc.GetString(bytes) }
        catch(ArgumentException) { return false; }
        return true;
    }
    

    如果在一个zip中的所有文件名上运行,您可以确定它是否在任何地方失败,在这种情况下,您可以断定这些名称没有保存为UTF-8。


    请注意,除了UTF-8之外,计算机的默认编码之间还有一个恼人的区别( Encoding.Default ,通常在美国和欧盟西部国家使用Windows-1252,但因地区和语言的不同而存在令人烦恼的差异)和您已经遇到的DOS-437编码。

    区分这些字符非常非常困难,可能需要实际检查超出字节0x80范围的每种编码是否产生正常的重音字符,以及这些字符通常不会在文件名中遇到的特殊字符。例如,许多DOS-437字符是用于在DOS中绘制半图形用户界面的帧。

    以下是DOS-437中的特殊字符(因此字节范围为0x80-0xFF),以供参考:

    80    ÇüéâäàåçêëèïîìÄÅ
    90    ÉæÆôöòûùÿÖÜ¢£¥₧ƒ
    A0    áíóúñѪº¿⌐¬½¼¡«»
    B0    ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐
    C0    └┴┬├─┼╞╟╚╔╩╦╠═╬╧
    D0    ╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀
    E0    αßΓπΣσµτΦΘΩδ∞φε∩
    F0    ≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ 
    

    在Windows-1252中:

    80    €�‚ƒ„…†‡ˆ‰Š‹Œ�Ž�
    90    �‘’“”•–—˜™š›œ�žŸ
    A0     ¡¢£¤¥¦§¨©ª«¬�®¯
    B0    °±²³´µ¶·¸¹º»¼½¾¿
    C0    ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
    D0    ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
    E0    àáâãäåæçèéêëìíîï
    F0    ðñòóôõö÷øùúûüýþÿ
    

    其中一些甚至不可打印,因此更容易打印。

    如您所见,通常DOS-437的大多数重音字符位于0x80-0xA5区域(测试版为0xE1,在德国通常用作 eszett ),而Win-1252几乎所有这些都位于0xC0-0xFF区域。如果确定了这些区域,您可以创建一个扫描机制来评估它似乎倾向于哪种编码,只需计算每个区域的预期范围内外的数量。


    请注意 Char 在c中#表示unicode字符,无论它是以字节的形式从何处加载的,并且unicode字符具有某些分类,您可以通过编程方式查找这些分类,以区分普通字母(可能带有变音符号)和各种特殊字符(简单示例:我知道其中一种是“空白字符”)。可能值得研究该系统,以自动化确定“正常语言字符”是什么的过程。