The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



Индекс форумов
Составление сообщения

Исходное сообщение
"Раздел полезных советов: Работа с русскими именами файлов в ..."
Отправлено auto_tips, 30-Ноя-10 23:16 
Одна из неожиданных проблем, возникающих при обмене файлами с пользователями Windows - странное поведение ZIP-архивов. Казалось бы, достаточно правильно настроить кодировки... Не тут-то было!

Для текстовых файлов достаточно найти редактор с выбором кодировки, для дисков можно указать кодировку при монтировании, более "продвинутые" форматы архивов (RAR, 7zip) тоже как-то решают эту проблему; и только ZIP, самый распространённый и "самый совместимый" архиватор, почему-то неожиданно оказывается несовместимым в принципе, стоит именам файлов выйти за пределы ASCII.

Есть мнение, что в архивы ZIP имена файлов пишутся в кодировке файловой системы, и дескать, отсюда и проблемы - в Windows одна кодировка, а в Linux другая. И виноват в том устаревший архивный формат и сделать с этим ничего нельзя, а если очень хочется - переименовывать распакованные файлы скриптами и прочими костылями. Что ж, попробуем.

Однако попытка увидеть имена файлов путём перекодировки вида

   ls -N | iconv -f cp866

заканчивается провалом. Ладно, не подошла 866, перебираем все известные русские кодировки и все виды юникода - имена файлов остаются нечитаемыми. Что же это за кодировка такая в зипе?!

Поиски в сети дают результат - оказывается, надо так:

   ls -N | iconv -f cp1252 -t cp850 | iconv -f cp866

Перекодировать распакованные файлы в utf-8 можно следующей командой:

   find . -type f -exec sh -c 'np=`echo {}|iconv -f cp1252 -t cp850| iconv -f cp866`; mv "{}" "$np"' \;

Битые имена файлов уходят, остаётся вопрос - неужели в зипе правда такая странная кодировка? Что-то сомнительно.

Ищем дальше и натыкаемся на разгадку. http://www.linuxfromscratch.org/blfs/view/cvs/general/unzip....

"[]The UnZip package assumes that filenames stored in the ZIP archives created on non-Unix systems are encoded in CP850, and that they should be converted to ISO-8859-1 when writing files onto the filesystem. Such assumptions are not always valid. In fact, inside the ZIP archive, filenames are encoded in the DOS codepage that is in use in the relevant country, and the filenames on disk should be in the locale encoding. In MS Windows, the OemToChar() C function (from User32.DLL) does the correct conversion (which is indeed the conversion from CP850 to a superset of ISO-8859-1 if MS Windows is set up to use the US English language), but there is no equivalent in Linux.

When using unzip to unpack a ZIP archive containing non-ASCII filenames, the filenames are damaged because unzip uses improper conversion when any of its encoding assumptions are incorrect. For example, in the ru_RU.KOI8-R locale, conversion of filenames from CP866 to KOI8-R is required, but conversion from CP850 to ISO-8859-1 is done, which produces filenames consisting of undecipherable characters instead of words (the closest equivalent understandable example for English-only users is rot13).[]"

Другими словами, имена файлов в ZIP-архиве хранятся в кодировке DOS, соответствующей языку локали. В Windows эта кодировка может быть получена соответствующей функцией, а для прочих систем авторы Info-ZIP решили не возиться и схалтурили - сделали безальтернативное преобразование cp850=>cp1252. Вот, где зарыта собака! Нет никакой "уникальной кодировки ZIP", там обычная 866 (для русской локали). Во всём прочем виноват не устаревший формат, а версия unzip от Info-ZIP для *nix, которая неправильно работает со всеми локалями, отличными от западноевропейских. Что делать?

Патчить. Можно, конечно, обойтись разовым переименованием, но только в разовых случаях. Если такие архивы встречаются часто, или их надо создавать, выбора не остаётся, нужен нормальный инструмент, а не костыли. В сети есть разные патчи для zip и unzip от разных авторов и для различных версий, однако многие из них устарели, а некоторые небеспроблемны. Я остановился на патчах от АльтЛинукса.

Проблему определения кодировки DOS они решили путём использования своей библиотеки
[[http://www.freesource.info/wiki/Lokalizacija/NATSPECDescription libnatspec]], которую перед этим придётся установить, брать можно тут: http://sourceforge.net/projects/natspec/
После её установки актуальные кодировки локали можно проверить командой

   natspec -i

Патч для unzip-6.0 подошел почти гладко, осталось исправить только две мелких детали. Патчи для zip оказались для предыдущей версии, поэтому пришлось повозиться немного больше, однако оно того стоило - теперь я могу спокойно распаковывать созданные в Windows zip-архивы просто командой unzip, и точно так же упаковывать командой zip, не опасаясь битой кодировки на том конце.

Итак, качаем исходник последней стабильной версии unzip [[ftp://ftp.info-zip.org/pub/infozip/src/unzip60.tgz unzip60.tgz]] и исправленную версию патча [[https://www.opennet.ru/soft/zip_rus/unzip60-natspec-mod.diff.gz unzip60-natspec-mod.diff.gz]], распаковываем исходник, переходим в его директорию, патчим, собираем и устанавливаем:

   zcat ../unzip60-natspec-mod.diff.gz | patch -p1
   make -f unix/Makefile generic_gcc

и от рута

   make -f unix/Makefile install

После этого unzip должен правильно распаковывать zip-архивы с русскими именами файлов, и правильно же выводить их в консоли.

Теперь то же самое с zip - берём последнюю версию [[ftp://ftp.info-zip.org/pub/infozip/src/zip30.tgz zip30.tgz]], и к нему мой патч
[[https://www.opennet.ru/soft/zip_rus/zip30-natspec-asdos-mod.d... natspec-asdos-mod.diff.gz]].
Распаковываем исходник, и в его директории:

   zcat ../zip30-natspec-asdos-mod.diff.gz | patch -p1
   make -f unix/Makefile generic_gcc

и от рута

   make -f unix/Makefile install

Теперь мы можем упаковывать zip-архивы в виде, полностью совместимом с проводником Windows и даже с TotalCommander. С последним оказалось, как ни странно, даже больше проблем - он требовал архив не просто в кодировке DOS, а непременно с именами в формате DOS, часть патча "asdos" именно для этого. Что особенно забавно, в TotalCommander использован код всё того же проекта Info-ZIP.

Возможно, некоторые спросят - зачем столько возни с этим морально устаревшим зипом, когда полно приличных архиваторов на любой вкус? Ответ - для совместимости, больше ни для чего ZIP и не нужен. А раз так, то пускай он делает своё дело как надо, а не как всегда :)

URL:
Обсуждается: https://www.opennet.ru/tips/info/2494.shtml

 

Ваше сообщение
Имя*:
EMail:
Для отправки ответов на email укажите знак ! перед адресом, например, !user@host.ru (!! - не показывать email).
Более тонкая настройка отправки ответов производится в профиле зарегистрированного участника форума.
Заголовок*:
Сообщение*:
 
При общении не допускается: неуважительное отношение к собеседнику, хамство, унизительное обращение, ненормативная лексика, переход на личности, агрессивное поведение, обесценивание собеседника, провоцирование флейма голословными и заведомо ложными заявлениями. Не отвечайте на сообщения, явно нарушающие правила - удаляются не только сами нарушения, но и все ответы на них. Лог модерирования.



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру