Как создать zip-архив каталога - PullRequest
367 голосов
/ 06 декабря 2009

Как я могу создать zip-архив структуры каталогов в Python?

Ответы [ 21 ]

712 голосов
/ 03 сентября 2014

Самый простой способ - использовать shutil.make_archive. Он поддерживает форматы zip и tar.

import shutil
shutil.make_archive(output_filename, 'zip', dir_name)

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

434 голосов
/ 06 декабря 2009

Как уже отмечали другие, вы должны использовать zipfile . Документация говорит вам, какие функции доступны, но не объясняет, как вы можете использовать их для архивирования всего каталога. Я думаю, что это проще всего объяснить с помощью некоторого примера кода:

#!/usr/bin/env python
import os
import zipfile

def zipdir(path, ziph):
    # ziph is zipfile handle
    for root, dirs, files in os.walk(path):
        for file in files:
            ziph.write(os.path.join(root, file))

if __name__ == '__main__':
    zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
    zipdir('tmp/', zipf)
    zipf.close()

Адаптировано из: http://www.devshed.com/c/a/Python/Python-UnZipped/

56 голосов
/ 06 декабря 2009

Чтобы добавить содержимое mydirectory в новый zip-файл, включая все файлы и подкаталоги:

import os
import zipfile

zf = zipfile.ZipFile("myzipfile.zip", "w")
for dirname, subdirs, files in os.walk("mydirectory"):
    zf.write(dirname)
    for filename in files:
        zf.write(os.path.join(dirname, filename))
zf.close()
44 голосов
/ 31 марта 2016

Как мне создать zip-архив структуры каталогов в Python?

В скрипте Python

В Python 2.7+ shutil имеет функцию make_archive.

from shutil import make_archive
make_archive(
  'zipfile_name', 
  'zip',           # the archive format - or tar, bztar, gztar 
  root_dir=None,   # root for archive - current working dir if None
  base_dir=None)   # start archiving from here - cwd if None too

Здесь заархивированный архив будет называться zipfile_name.zip. Если base_dir дальше от root_dir, это исключит файлы, не входящие в base_dir, но все же заархивирует файлы в родительских каталогах до root_dir.

У меня была проблема с проверкой этого на Cygwin с 2.7 - ему нужен аргумент root_dir, для cwd:

make_archive('zipfile_name', 'zip', root_dir='.')

Использование Python из оболочки

Вы можете сделать это с помощью Python из оболочки, также используя модуль zipfile:

$ python -m zipfile -c zipname sourcedir

Где zipname - это имя файла назначения, который вы хотите (добавьте .zip, если вы хотите, он не будет делать это автоматически), а sourcedir - это путь к каталогу.

Архивирование Python (или просто не хочу родительский каталог):

Если вы пытаетесь заархивировать пакет python с __init__.py и __main__.py, и вам не нужен родительский каталог, это

$ python -m zipfile -c zipname sourcedir/*

И

$ python zipname

запустит пакет. (Обратите внимание, что вы не можете запускать подпакеты в качестве точки входа из архива.)

Архивирование приложения Python:

Если у вас есть python3.5 +, и вы хотите заархивировать пакет Python, используйте zipapp :

$ python -m zipapp myapp
$ python myapp.pyz
29 голосов
/ 13 июня 2013

Эта функция рекурсивно архивирует дерево каталогов, сжимает файлы и записывает правильные относительные имена файлов в архиве. Архивные записи такие же, как и в zip -r output.zip source_dir.

import os
import zipfile
def make_zipfile(output_filename, source_dir):
    relroot = os.path.abspath(os.path.join(source_dir, os.pardir))
    with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip:
        for root, dirs, files in os.walk(source_dir):
            # add directory (needed for empty dirs)
            zip.write(root, os.path.relpath(root, relroot))
            for file in files:
                filename = os.path.join(root, file)
                if os.path.isfile(filename): # regular files only
                    arcname = os.path.join(os.path.relpath(root, relroot), file)
                    zip.write(filename, arcname)
15 голосов
/ 12 октября 2018

Используйте shutil, который является частью набора стандартных библиотек python. Использовать shutil очень просто (см. Код ниже):

  • 1-й аргумент: имя файла результирующего файла zip / tar,
  • 2-й аргумент: zip / tar,
  • 3-й аргумент: dir_name

Код:

import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
11 голосов
/ 27 апреля 2013

Чтобы добавить сжатие к результирующему zip-файлу, просмотрите эту ссылку .

Вам необходимо изменить:

zip = zipfile.ZipFile('Python.zip', 'w')

до

zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
5 голосов
/ 10 июня 2013

Я внес некоторые изменения в код , данный Марком Байерсом . Функция ниже также добавляет пустые каталоги, если они у вас есть. Примеры должны прояснить, какой путь добавляется в zip.

#!/usr/bin/env python
import os
import zipfile

def addDirToZip(zipHandle, path, basePath=""):
    """
    Adding directory given by \a path to opened zip file \a zipHandle

    @param basePath path that will be removed from \a path when adding to archive

    Examples:
        # add whole "dir" to "test.zip" (when you open "test.zip" you will see only "dir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir')
        zipHandle.close()

        # add contents of "dir" to "test.zip" (when you open "test.zip" you will see only it's contents)
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir', 'dir')
        zipHandle.close()

        # add contents of "dir/subdir" to "test.zip" (when you open "test.zip" you will see only contents of "subdir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir/subdir', 'dir/subdir')
        zipHandle.close()

        # add whole "dir/subdir" to "test.zip" (when you open "test.zip" you will see only "subdir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir/subdir', 'dir')
        zipHandle.close()

        # add whole "dir/subdir" with full path to "test.zip" (when you open "test.zip" you will see only "dir" and inside it only "subdir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir/subdir')
        zipHandle.close()

        # add whole "dir" and "otherDir" (with full path) to "test.zip" (when you open "test.zip" you will see only "dir" and "otherDir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir')
        addDirToZip(zipHandle, 'otherDir')
        zipHandle.close()
    """
    basePath = basePath.rstrip("\\/") + ""
    basePath = basePath.rstrip("\\/")
    for root, dirs, files in os.walk(path):
        # add dir itself (needed for empty dirs
        zipHandle.write(os.path.join(root, "."))
        # add files
        for file in files:
            filePath = os.path.join(root, file)
            inZipPath = filePath.replace(basePath, "", 1).lstrip("\\/")
            #print filePath + " , " + inZipPath
            zipHandle.write(filePath, inZipPath)

Выше простая функция, которая должна работать для простых случаев. Вы можете найти более элегантный класс в моем Gist: https://gist.github.com/Eccenux/17526123107ca0ac28e6

2 голосов
/ 02 октября 2015

У меня есть другой пример кода, который может помочь, используя python3, pathlib и zipfile. Должно работать в любой ОС.

from pathlib import Path
import zipfile
from datetime import datetime

DATE_FORMAT = '%y%m%d'


def date_str():
    """returns the today string year, month, day"""
    return '{}'.format(datetime.now().strftime(DATE_FORMAT))


def zip_name(path):
    """returns the zip filename as string"""
    cur_dir = Path(path).resolve()
    parent_dir = cur_dir.parents[0]
    zip_filename = '{}/{}_{}.zip'.format(parent_dir, cur_dir.name, date_str())
    p_zip = Path(zip_filename)
    n = 1
    while p_zip.exists():
        zip_filename = ('{}/{}_{}_{}.zip'.format(parent_dir, cur_dir.name,
                                             date_str(), n))
        p_zip = Path(zip_filename)
        n += 1
    return zip_filename


def all_files(path):
    """iterator returns all files and folders from path as absolute path string
    """
    for child in Path(path).iterdir():
        yield str(child)
        if child.is_dir():
            for grand_child in all_files(str(child)):
                yield str(Path(grand_child))


def zip_dir(path):
    """generate a zip"""
    zip_filename = zip_name(path)
    zip_file = zipfile.ZipFile(zip_filename, 'w')
    print('create:', zip_filename)
    for file in all_files(path):
        print('adding... ', file)
        zip_file.write(file)
    zip_file.close()


if __name__ == '__main__':
    zip_dir('.')
    print('end!')
2 голосов
/ 06 декабря 2009

Вы, вероятно, хотите посмотреть на модуль zipfile; есть документация на http://docs.python.org/library/zipfile.html.

Вы также можете os.walk() индексировать структуру каталогов.

...