Использование zipfile для архивирования содержимого каталога при пропуске файлов из списка - PullRequest
0 голосов
/ 22 декабря 2018

Я использую zipfile для создания архива всех файлов в каталоге (рекурсивно, с сохранением структуры каталогов, включая пустые папки) и хочу, чтобы процесс пропускал имена файлов, указанные в списке.

Это базовая функция, которая выполняет os.walking по каталогу и добавляет все содержащиеся в нем файлы и каталоги в архив.

def zip_dir(path):
    zipname = str(path.rsplit('/')[-1]) + '.zip'
    with zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED) as zf:
        if os.path.isdir(path):
            for root, dirs, files in os.walk(path):
                for file_or_dir in files + dirs:
                    zf.write(os.path.join(root, file_or_dir),
                            os.path.relpath(os.path.join(root, file_or_dir),
                            os.path.join(path, os.path.pardir)))
        elif os.path.isfile(filepath):
            zf.write(os.path.basename(filepath))
    zf.printdir()
    zf.close()

Мы видим, что код также должен иметь возможность обрабатывать отдельные файлы, но этоглавным образом, часть, касающаяся каталогов, которые нас интересуют.

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

skiplist = ['.DS_Store', 'tempfile.tmp']

Что такоелучший и самый чистый способ достичь этого?

Я попытался использовать zip, который был несколько успешным, но по какой-то причине он исключает пустые папки (должны быть включены пустые папки).Я не уверен, почему это происходит.

skiplist = ['.DS_Store', 'tempfile.tmp']
for root, dirs, files in os.walk(path):
    for (file_or_dir, skipname) in zip(files + dirs, skiplist):
        if skipname not in file_or_dir:
            zf.write(os.path.join(root, file_or_dir),
                    os.path.relpath(os.path.join(root, file_or_dir),
                    os.path.join(path, os.path.pardir)))

Было бы также интересно узнать, есть ли у кого-нибудь умная идея по добавлению возможности пропускать определенные расширения файлов, возможно, что-то вроде .endswith('.png'), но я 'Я не совсем уверен, как включить его вместе с существующим скиплистом.

Буду также признателен за любые другие общие замечания относительно функции и, если она действительно работает, как ожидается, без сюрпризов, а также за любые предложения по оптимизации илиулучшения.

1 Ответ

0 голосов
/ 22 декабря 2018

Вы можете просто проверить, не находится ли файл в skiplist:

skiplist = {'.DS_Store', 'tempfile.tmp'}

for root, dirs, files in os.walk(path):
    for file in files + dirs:
        if file not in skiplist:
            zf.write(os.path.join(root, file),
                     os.path.relpath(os.path.join(root, file),
                     os.path.join(path, os.path.pardir)))

Это гарантирует, что файлы в skiplist не будут добавлены в архив.

Другая оптимизация - сделать skiplist набором, на случай, если он станет очень большим, и вы захотите использовать поиск O (1) с постоянным временем вместо линейного поиска O (N) при использовании списка.

Вы можете исследовать это подробнее в TimeComplexity , который показывает временные сложности различных операций Python над структурами данных.

Что касается расширений, вы можете использовать os.path.splitext() для извлечения расширения и использовать ту же логику, что и выше:

from os.path import splitext

extensions = {'.png', '.txt'}

for root, dirs, files in os.walk(path):
    for file in files:
        _, extension = splitext(file)
        if extension not in extensions:
            zf.write(os.path.join(root, file),
                     os.path.relpath(os.path.join(root, file),
                     os.path.join(path, os.path.pardir)))

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

from os.path import splitext

extensions = {'.png', '.txt'}
skiplist = {'.DS_Store', 'tempfile.tmp'}

for root, dirs, files in os.walk(path):
    for file in files:
        _, extension = splitext(file)
        if file not in skiplist and extension not in extensions:
            zf.write(os.path.join(root, file),
                     os.path.relpath(os.path.join(root, file),
                     os.path.join(path, os.path.pardir)))

    for directory in dirs:
        if directory not in skiplist:
            zf.write(os.path.join(root, directory),
                     os.path.relpath(os.path.join(root, directory),
                     os.path.join(path, os.path.pardir))) 

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

...