Как я могу создать zip / tgz в Linux, чтобы в Windows были правильные имена файлов?

28069
kolypto

В настоящее время tar -zcf arch.tgz files/*кодирует имена файлов в UTF, поэтому пользователи Windows видят все испорченные символы в именах файлов, которые не являются английскими, и ничего не могут с этим поделать.

zip -qq -r arch.zip files/* имеет такое же поведение.

Как мне создать архив zip / tgz, чтобы при извлечении пользователями Windows в нем были правильно закодированы все имена файлов?

25

6 ответов на вопрос

25
Alexei Osipov

Вот простой скрипт Python, который я написал для распаковки tar-файлов из UNIX в Windows:

import tarfile  archive_name = "archive_name.tar"  def recover(name): return unicode(name, 'utf-8')  tar = tarfile.open(name=archive_name, mode='r', bufsize=16*1024) updated = [] for m in tar.getmembers(): m.name = recover(m.name) updated.append(m)  tar.extractall(members=updated) tar.close() 
Потрясающие! Этот скрипт помог мне конвертировать EUC-JP-кодированный tar-файл, созданный на старом сервере Solaris. wm_eddie 13 лет назад 0
Сэр, вы спасли мою жизнь. Будьте здоровы :) user1576772 8 лет назад 0
24
bobince

В настоящее время tar кодирует имена файлов в UTF

На самом деле tar вообще не кодирует / не декодирует имена файлов, он просто копирует их из файловой системы как есть. Если ваша локаль основана на UTF-8 (как во многих современных дистрибутивах Linux), это будет UTF-8. К сожалению, системная кодовая страница окна Windows никогда не является UTF-8, поэтому имена всегда будут искажены, за исключением таких инструментов, как WinRAR, которые позволяют изменять кодировку.

Таким образом, невозможно создать ZIP-файл с именами, отличными от ASCII, которые работают в разных версиях Windows и поддерживают встроенные сжатые папки.

Недостатком форматов tar и zip является отсутствие фиксированной или предоставленной информации о кодировке, поэтому не-ASCII-символы всегда будут непереносимыми. Если вам нужен формат архива не ASCII, вам придется использовать один из более новых форматов, например, последние 7z или rar. К сожалению, они все еще шаткие; в 7zip вам нужен -mcuпереключатель, и rar по-прежнему не будет использовать UTF-8, если не обнаружит символы, отсутствующие в кодовой странице.

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

Большое спасибо! К сожалению, большинство пользователей ничего не знают о 7z, а rar является проприетарным :( kolypto 14 лет назад 0
Да, это проблема. ZIP, безусловно, является наиболее удобным решением для пользователей, поскольку все современные ОС имеют приятную встроенную поддержку пользовательского интерфейса. К сожалению, проблема с кодировкой в ​​настоящее время не очень разрешима в ZIP (и даже в других форматах архивов это все еще проблематично). bobince 14 лет назад 0
8
Sys

Проблема с использованием в Linux по умолчанию tar(GNU tar) решена ... добавлением --format=posixпараметра при создании файла.

Например:
tar --format=posix -cf

В Windows для распаковки файлов я использую bsdtar .

В https://lists.gnu.org/archive/html/bug-tar/2005-02/msg00018.html написано (с 2005 года !!):

> Я прочитал что-то в ChangeLog о поддержке UTF-8. Что
это значит?
> Я не нашел способа создать архив, который был бы взаимозаменяемым
> между разными локалями.

При создании архивов в формате POSIX.1-2001 (tar --format = posix или --format = pax) tar преобразует имена файлов из текущей локали в UTF-8, а затем сохраняет их в архиве. При извлечении выполняется обратная операция.

PS Вместо того, чтобы печатать, --format=posixвы можете печатать -H pax, что короче.

5
quack quixote

Я полагаю, что у вас возникли проблемы с самим форматом контейнера Zip. Тар может страдать от той же проблемы.

Используйте 7zip ( .7z) или RAR ( .rar) форматы архивов вместо. Оба доступны для Windows и Linux; p7zipпрограммное обеспечение обрабатывает оба формата.

Я просто проверял создание .7z, .rar, .zipи .tarфайлы на обоих WinXP и Debian 5, а .7zи .rarхранения файлов / имен файлов правильно восстановить в то время как .zipи .tarфайлы не делают. Неважно, какая система используется для создания тестового архива.

4
damjan

В POSIX-1.2001 указано, как TAR использует UTF-8.

Начиная с 2007 года в версии журнала изменений 6.3.0 в приложении PKZIP APPNOTE.TXT ( http://www.pkware.com/documents/casestudies/APPNOTE.TXT ) указано, как ZIP использует UTF-8.

Только то, какие инструменты поддерживают эти стандарты должным образом, остается открытым вопросом.

4
dmitry_romanov

У меня были проблемы с распаковкой tarи zipфайлами, которые я получаю от пользователей Windows. Хотя я не отвечаю на вопрос «как создать архив, который будет работать», приведенные ниже скрипты помогают правильно распаковывать tarи zipфайлы независимо от оригинальной ОС.

ВНИМАНИЕ: необходимо настроить кодировку источника вручную ( cp1251, cp866в примерах ниже). Параметры командной строки могут быть хорошим решением в будущем.

Деготь:

#!/usr/bin/env python  import tarfile import codecs import sys  def recover(name): return codecs.decode(name, 'cp1251')  for tar_filename in sys.argv[1:]: tar = tarfile.open(name=tar_filename, mode='r', bufsize=16*1024) updated = [] for m in tar.getmembers(): m.name = recover(m.name) updated.append(m) tar.extractall(members=updated) tar.close() 

Почтовый индекс:

#!/usr/bin/env python  import zipfile import os import codecs import sys  def recover(name): return codecs.decode(name, 'cp866')  for filename in sys.argv[1:]: archive = zipfile.ZipFile(filename, 'r') infolist = archive.infolist() for i in infolist: f = recover(i.filename) print f if f.endswith("/"): os.makedirs(os.path.dirname(f)) else: open(f, 'w').write(archive.read(i)) archive.close() 

UPD 2018-01-02 : Я использую chardetпакет, чтобы угадать правильную кодировку необработанного фрагмента данных. Теперь скрипт работает "из коробки" на всех моих плохих архивах, а также на хороших.

Что следует отметить:

  1. Все имена файлов извлекаются и объединяются в одну строку, чтобы создать больший фрагмент текста для механизма кодирования. Это означает, что несколько имен файлов, закрученных по-разному, могут испортить предположение.
  2. Специальный быстрый путь был использован для обработки хорошего текста Unicode ( chardetне работает с обычным объектом Unicode).
  3. Тесты добавляются для тестирования и демонстрации того, что нормализатор распознает любую кодировку на достаточно коротких строках.

Окончательный вариант:

#!/usr/bin/env python2 # coding=utf-8  import zipfile import os import codecs import sys  import chardet   def make_encoding_normalizer(txt): u''' Takes raw data and returns function to normalize encoding of the data. * `txt` is either unicode or raw bytes; * `chardet` library is used to guess the correct encoding.  >>> n_unicode = make_encoding_normalizer(u"Привет!") >>> print n_unicode(u"День добрый") День добрый  >>> n_cp1251 = make_encoding_normalizer(u"Привет!".encode('cp1251')) >>> print n_cp1251(u"День добрый".encode('cp1251')) День добрый >>> type(n_cp1251(u"День добрый".encode('cp1251'))) <type 'unicode'> ''' if isinstance(txt, unicode): return lambda text: text  enc = chardet.detect(txt)['encoding'] return lambda file_name: codecs.decode(file_name, enc)   for filename in sys.argv[1:]: archive = zipfile.ZipFile(filename, 'r') infolist = archive.infolist()  probe_txt = "\n".join(i.filename for i in infolist) normalizer = make_encoding_normalizer(probe_txt)  for i in infolist: print i.filename f = normalizer(i.filename) print f dirname = os.path.dirname(f) if dirname: assert os.path.abspath(dirname).startswith(os.path.abspath(".")), \ "Security violation" if not os.path.exists(dirname): os.makedirs(dirname) if not f.endswith("/"): open(f, 'w').write(archive.read(i)) archive.close()   if __name__ == '__main__' and len(sys.argv) == 1: # Hack for Python 2.x to support unicode source files as doctest sources. reload(sys) sys.setdefaultencoding("UTF-8")  import doctest doctest.testmod()  print "If there are no messages above, the script passes all tests." 
Спасибо за ваши программы! К сожалению, программа Zip не работает в Python 3, но работает в Python 2. beroal 6 лет назад 0
@beroal, я обновил скрипт. Теперь он использует движок, разработанный Mozilla для Firefox, для автоматического определения кодировки. dmitry_romanov 6 лет назад 0

Похожие вопросы