Кодирование файлов внутри zip (C# / ionic-zip)

У нас проблема с кодировкой файлов внутри 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('¥', 'Ø');
}

Это работает уже некоторое время, и все было хорошо.

Но, поскольку всегда есть "но", мы не пробовали его с файлом, сжатым с помощью инструмента по умолчанию в Mac OSX. Итак, теперь у нас возникла новая проблема. При использовании æ, ø и å кодировка UTF-8!Так что я могу заставить его работать, если я знаю, где был сжат zip, но есть ли какой-нибудь простой способ обнаружить или нормализовать кодировку внутри zip?

1 ответ

Решение

Обнаружение кодирования - всегда сложное дело, но UTF8 имеет строгие побитовые правила о том, какие значения ожидаются в допустимой последовательности, и вы можете инициализировать объект UTF8Encoding таким способом, который завершится ошибкой, выдав исключение, если эти последовательности неверны:

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.

Для справки, это специальные символы (поэтому диапазон байтов 0x80-0xFF) в DOS-437:

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 имеют определенные классификации, которые вы можете искать программно, различая их между обычными буквами (возможно, с диакритическими знаками) и различными классами специальных символов (простой пример: I знаю, один из этих классов "пробельные символы"). Возможно, стоит заглянуть в эту систему, чтобы автоматизировать процесс определения "символов нормального языка".

Другие вопросы по тегам