Tarfile / Zipfile extractall () изменяет имя файла некоторых файлов - PullRequest
1 голос
/ 25 марта 2019

Здравствуйте. В настоящее время я работаю над инструментом, который должен извлекать некоторые файлы .tar.

По большей части прекрасно работает, но у меня есть одна проблема:

Некоторые файлы .tar и .zip имеют имена, которые содержат "недопустимые" символы (f.ex ":"). Эта программа должна работать на машинах с Windows, поэтому мне приходится иметь дело с этим.

Есть ли способ изменить имя некоторых файлов в извлеченном выводе, если он содержит ":" или другой недопустимый символ Windows.

Моя текущая реализация:

def read_zip(filepath, extractpath):
    with zipfile.ZipFile(filepath, 'r') as zfile:
        contains_bad_char = False
        for finfo in zfile.infolist():
            if ":" in finfo.filename:
                contains_bad_char = True
        if not contains_bad_char:
            zfile.extractall(path=extractpath)


def read_tar(filepath, extractpath):
    with tarfile.open(filepath, "r:gz") as tar:
        contains_bad_char = False
        for member in tar.getmembers():
            if ":" in member.name:
                contains_bad_char = True
        if not contains_bad_char:
            tar.extractall(path=extractpath)

Так что в настоящее время я просто игнорирую все эти выводы, что не идеально.

Чтобы лучше описать, о чем я прошу, приведу небольшой пример:

file_with_files.tar -> small_file_1.txt
                    -> small_file_2.txt
                    -> annoying:file_1.txt
                    -> annoying:file_1.txt

Следует извлечь до

file_with_files -> small_file_1.txt
                -> small_file_2.txt
                -> annoying_file_1.txt
                -> annoying_file_1.txt

Является ли единственным решением перебирать каждый файлобъект в сжатом файле и извлекать его по одному или есть более элегантное решение?

1 Ответ

1 голос
/ 26 марта 2019

Согласно [Python 3]: ZipFile. извлечение ( элемент, путь = нет, pwd = нет ) :

В Windows недопустимые символы (:, <, >, |, ", ? и *) заменены подчеркиванием (_).

Итак, все уже решено:

>>> import os
>>> import zipfile
>>>
>>> os.getcwd()
'e:\\Work\\Dev\\StackOverflow\\q055340013'
>>> os.listdir()
['arch.zip']
>>>
>>> zf = zipfile.ZipFile("arch.zip")
>>> zf.namelist()
['file0.txt', 'file:1.txt']
>>> zf.extractall()
>>> zf.close()
>>>
>>> os.listdir()
['arch.zip', 'file0.txt', 'file_1.txt']

Быстрый просмотр tarfile (источник и документ) не выявил ничего подобного(и я не был бы очень удивлен, если бы не было, поскольку формат .tar в основном используется на Nix ), поэтому вам придется делать это вручную.Все не так просто, как я ожидал, поскольку tarfile не предоставляет возможности извлечения члена под другим именем, как zipfile .
В любом случае, вот фрагмент кода (у меня были zipfile и tarfile в качестве муз или источников вдохновения):

def read_tar(filepath, extractpath="."):
    win_illegal = ':<>|"?*'
    table = str.maketrans(win_illegal, '_' * len(win_illegal))
    with tarfile.open(filepath, "r:gz") as tar:
        for member in tar.getmembers():
            if member.isdir():
                os.makedirs(member.path.translate(table))
            else:
                with open(os.path.join(extractpath, member.path.translate(table)), "wb") as fout:
                    fout.write(tarfile.ExFileObject(tar, member).read())

Обратите внимание, что приведенный выше кодработает для простых .tar файлов (с простыми элементами, включая каталоги), но я не проверял его на прочность .

@EDIT0 :

Добавлена ​​обработка каталогов.

@ EDIT1 :

Отправлено [Python.Bugs]: tarfile: обработка недопустимых символов Windows (путь) в именах элементов архива .
Я не знаю, каким будет его исход, так как я представил несколько проблем (и исправлений для них), которые были более серьезными (на моем PoV ), но по разным причинам, они были отклонены.

...