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