Як я можу створити zip / tgz в Linux таким чином, щоб у Windows були належні імена файлів?


26

Наразі tar -zcf arch.tgz files/*кодує назви файлів у UTF, тому користувачі Windows бачать усі зіпсовані символи файлів, які не є англійською мовою , і нічого не можуть з цим робити.

zip -qq -r arch.zip files/* має таку саму поведінку.

Як я можу створити zip / tgz архів, щоб коли користувачі Windows витягнули, всі файли файлів будуть правильно закодовані?

Відповіді:


24

В даний час смола кодує імена файлів в 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

Так, це проблема. ZIP на сьогоднішній день є найбільш корисним рішенням для користувачів, оскільки всі сучасні ОС мають приємну підтримку рідного інтерфейсу для нього. На жаль, проблема шаблонів не дуже вирішена сьогодні в ZIP-файлі (і навіть в інших форматах архіву - це все ще клопотно).
bobince

25

Ось простий скрипт 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

Сер, ви врятували мені життя. Бог тебе благослови :)
користувач1576772

8

Проблема, що використовує в 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

Я думаю, у вас виникають проблеми із самим форматом контейнера Zip. Дьоготь може страждати від тієї ж проблеми.

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

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


5

У мене виникли проблеми з розпакуванням 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

@beroal, я оновив сценарій. Тепер він використовує двигун, розроблений Mozilla для Firefox для автоматичного виявлення кодування.
dmitry_romanov

4

POSIX-1.2001 визначає, як TAR використовує UTF-8.

Станом на 2007 рік, редактор змін версії 6.3.0 у PKZIP APPNOTE.TXT ( http://www.pkware.com/documents/casestudies/APPNOTE.TXT ) вказав, як ZIP використовує UTF-8.

Лише, які інструменти належним чином підтримують ці стандарти, це залишається відкритим питанням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.