web-dev-qa-db-ja.com

ディレクトリのZipアーカイブを作成する方法

Pythonでディレクトリ構造のZipアーカイブを作成する方法を教えてください。

362
Martha Yi

他の人が指摘したように、あなたは zipfile を使うべきです。ドキュメンテーションはどんな機能が利用可能であるかをあなたに話します、しかし実際にあなたがディレクトリ全体をZipするためにそれらを使うことができる方法を説明しません。いくつかのコード例で説明するのが最も簡単だと思います。

#!/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 __== '__main__':
    zipf = zipfile.ZipFile('Python.Zip', 'w', zipfile.Zip_DEFLATED)
    zipdir('tmp/', zipf)
    zipf.close()

から適応: http://www.devshed.com/c/a/Python/Python-UnZipped/

428
Mark Byers

最も簡単な方法は shutil.make_archive を使うことです。 Zip形式とtar形式の両方をサポートしています。

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

ディレクトリ全体を圧縮するよりも複雑な作業(特定のファイルをスキップするなど)が必要な場合は、 zipfile モジュールを掘り下げる必要があります他の人が示唆しているように。

701
crdavis

すべてのファイルとサブディレクトリを含む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()
56
Ben James

Pythonでディレクトリ構造のZipアーカイブを作成する方法を教えてください。

Pythonスクリプトで

Python 2.7以降では、shutilmake_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

ここでzip圧縮されたアーカイブはzipfile_name.Zipという名前になります。 base_dirroot_dirからさらに離れている場合は、base_dirにないファイルを除外しますが、それでも親ディレクトリのroot_dirまでのファイルをアーカイブします。

私は2.7でCygwinでこれをテストする問題を抱えていました - それはcwdのためにroot_dir引数を望みます:

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

シェルからPythonを使う

zipfileモジュールを使ってシェルからPythonでこれを行うことができます。

$ python -m zipfile -c zipname sourcedir

zipnameはあなたが欲しい目的ファイルの名前であり(あなたがそれを望むなら.Zipを追加します、それは自動的にそれをしません)そしてsourcedirはディレクトリへのパスです。

Pythonを圧縮する(あるいは単に親ディレクトリを使いたくない):

__init__.py__main__.pyを使ってpythonパッケージをZip圧縮しようとしていて、親ディレクトリが欲しくない場合は、

$ python -m zipfile -c zipname sourcedir/*

そして

$ python zipname

パッケージを実行します。 (zip形式のアーカイブからエントリポイントとしてサブパッケージを実行することはできません。)

Pythonアプリを圧縮する:

Python3.5以降を使用していて、特にPythonパッケージを圧縮したい場合は、 zipapp を使用してください。

$ python -m zipapp myapp
$ python myapp.pyz
44
Aaron Hall

この関数は、ディレクトリツリーを再帰的にZip圧縮し、ファイルを圧縮して、アーカイブに正しい相対ファイル名を記録します。アーカイブのエントリは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)
29

Python標準ライブラリセットの一部であるshutilを使用してください。 shutilの使い方はとても簡単です(下記のコードを参照)。

  • 1番目の引数:結果のZip/tarファイルのファイル名、
  • 第二引数:ジップ/タール、
  • 3番目の引数:dir_name

コード:

import shutil
shutil.make_archive('/home/user/Desktop/Filename','Zip','/home/username/Desktop/Directory')
15

結果のZipファイルに圧縮を追加するには、このリンクをチェック してください

変更する必要があります。

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

Zip = zipfile.ZipFile('Python.Zip', 'w', zipfile.Zip_DEFLATED)
11
E Smith

Mark Byersによって与えられた コードにいくつかの変更を加えました 。下記の機能は空のディレクトリを追加します。例は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)

上記は単純な場合に機能する単純な関数です。あなたは私の要旨でよりエレガントなクラスを見つけることができます: https://Gist.github.com/Eccenux/17526123107ca0ac28e6

5
Nux

おそらくzipfileモジュールを見たいでしょう。 http://docs.python.org/library/zipfile.html にドキュメントがあります。

os.walk()にディレクトリ構造のインデックスを付けることもできます。

2
me_and

Python3、pathlib、およびzipfileを使用して、役立つ可能性のある別のコード例があります。どのOSでも動作するはずです。

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 __== '__main__':
    Zip_dir('.')
    print('end!')
2
duncanmonty

現代のPython(3.6+)では、 pathlib モジュールを使用して、パスを簡潔にOOP風に処理し、 pathlib.Path.rglob() を再帰的グロビングに使用しています。私が言える限りでは、これはGeorge V. Reillyの答えと同じです。圧縮で圧縮すると、一番上の要素はディレクトリで、空のディレクトリを保持し、相対パスを使用します。

from pathlib import Path
from zipfile import Zip_DEFLATED, ZipFile

from os import PathLike
from typing import Union


def Zip_dir(Zip_name: str, source_dir: Union[str, PathLike]):
    src_path = Path(source_dir).expanduser().resolve(strict=True)
    with ZipFile(Zip_name, 'w', Zip_DEFLATED) as zf:
        for file in src_path.rglob('*'):
            zf.write(file, file.relative_to(src_path.parent))

注:オプションの型ヒントが示すように、Zip_nameをPathオブジェクトにすることはできません( は3.6.2 + で修正される予定です)。

1
monk-time

より多くの柔軟性を与えるために、名前でディレクトリ/ファイルを選択します。

import os
import zipfile

def zipall(ob, path, rel=""):
    basename = os.path.basename(path)
    if os.path.isdir(path):
        if rel == "":
            rel = basename
        ob.write(path, os.path.join(rel))
        for root, dirs, files in os.walk(path):
            for d in dirs:
                zipall(ob, os.path.join(root, d), os.path.join(rel, d))
            for f in files:
                ob.write(os.path.join(root, f), os.path.join(rel, f))
            break
    Elif os.path.isfile(path):
        ob.write(path, os.path.join(rel, basename))
    else:
        pass

ファイルツリーの場合:

.
├── dir
│   ├── dir2
│   │   └── file2.txt
│   ├── dir3
│   │   └── file3.txt
│   └── file.txt
├── dir4
│   ├── dir5
│   └── file4.txt
├── listdir.Zip
├── main.py
├── root.txt
└── selective.Zip

できます。 dir4root.txtのみを選択してください。

cwd = os.getcwd()
files = [os.path.join(cwd, f) for f in ['dir4', 'root.txt']]

with zipfile.ZipFile("selective.Zip", "w" ) as myzip:
    for f in files:
        zipall(myzip, f)

あるいは、スクリプト呼び出しディレクトリにlistdirを追加して、そこからすべてを追加します。

with zipfile.ZipFile("listdir.Zip", "w" ) as myzip:
    for f in os.listdir():
        if f == "listdir.Zip":
            # Creating a listdir.Zip in the same directory
            # will include listdir.Zip inside itself, beware of this
            continue
        zipall(myzip, f)
1
pbn

以下を試してみてください。私のために働いていました

import zipfile, os
zipf = "compress.Zip"  
def main():
    directory = r"Filepath"
    toZip(directory)
def toZip(directory):
    zippedHelp = zipfile.ZipFile(zipf, "w", compression=zipfile.Zip_DEFLATED )

    list = os.listdir(directory)
    for file_list in list:
        file_name = os.path.join(directory,file_list)

        if os.path.isfile(file_name):
            print file_name
            zippedHelp.write(file_name)
        else:
            addFolderToZip(zippedHelp,file_list,directory)
            print "---------------Directory Found-----------------------"
    zippedHelp.close()

def addFolderToZip(zippedHelp,folder,directory):
    path=os.path.join(directory,folder)
    print path
    file_list=os.listdir(path)
    for file_name in file_list:
        file_path=os.path.join(path,file_name)
        if os.path.isfile(file_path):
            zippedHelp.write(file_path)
        Elif os.path.isdir(file_name):
            print "------------------sub directory found--------------------"
            addFolderToZip(zippedHelp,file_name,path)


if __name__=="__main__":
    main()
1
Chandra

これは私のために働くNuxによって与えられた答えのバリエーションです:

def WriteDirectoryToZipFile( zipHandle, srcPath, zipLocalPath = "", zipOperation = zipfile.Zip_DEFLATED ):
    basePath = os.path.split( srcPath )[ 0 ]
    for root, dirs, files in os.walk( srcPath ):
        p = os.path.join( zipLocalPath, root [ ( len( basePath ) + 1 ) : ] )
        # add dir
        zipHandle.write( root, p, zipOperation )
        # add files
        for f in files:
            filePath = os.path.join( root, f )
            fileInZipPath = os.path.join( p, f )
            zipHandle.write( filePath, fileInZipPath, zipOperation )
1
M Katz

一般的なグラフィカルファイルマネージャのcompressフォルダのような機能が必要な場合は、次のコードを使用できます。 zipfile モジュールを使用します。このコードを使用すると、パスをルートフォルダとするZipファイルが作成されます。

import os
import zipfile

def zipdir(path, ziph):
    # Iterate all the directories and files
    for root, dirs, files in os.walk(path):
        # Create a prefix variable with the folder structure inside the path folder. 
        # So if a file is at the path directory will be at the root directory of the Zip file
        # so the prefix will be empty. If the file belongs to a containing folder of path folder 
        # then the prefix will be that folder.
        if root.replace(path,'') == '':
                prefix = ''
        else:
                # Keep the folder structure after the path folder, append a '/' at the end 
                # and remome the first character, if it is a '/' in order to have a path like 
                # folder1/folder2/file.txt
                prefix = root.replace(path, '') + '/'
                if (prefix[0] == '/'):
                        prefix = prefix[1:]
        for filename in files:
                actual_file_path = root + '/' + filename
                zipped_file_path = prefix + filename
                zipf.write( actual_file_path, zipped_file_path)


zipf = zipfile.ZipFile('Python.Zip', 'w', zipfile.Zip_DEFLATED)
zipdir('/tmp/justtest/', zipf)
zipf.close()
1
VGe0rge

Zipファイルを作成する機能.

def CREATEZIPFILE(zipname, path):
    #function to create a Zip file
    #Parameters: zipname - name of the Zip file; path - name of folder/file to be put in Zip file

    zipf = zipfile.ZipFile(zipname, 'w', zipfile.Zip_DEFLATED)
    zipf.setpassword(b"password") #if you want to set password to zipfile

    #checks if the path is file or directory
    if os.path.isdir(path):
        for files in os.listdir(path):
            zipf.write(os.path.join(path, files), files)

    Elif os.path.isfile(path):
        zipf.write(os.path.join(path), path)
    zipf.close()
0
sushh

Mark ByersのソリューションをReimundとMorten Zilmerのコメント(相対パスと空のディレクトリを含む)と統合することによって関数を作成しました。ベストプラクティスとして、withはZipFileのファイル構成で使用されます。

この関数は、圧縮されたディレクトリ名と '.Zip'拡張子を持つデフォルトのZipファイル名も用意します。したがって、それは1つの引数、つまり圧縮されるソースディレクトリでのみ動作します。

import os
import zipfile

def Zip_dir(path_dir, path_file_Zip=''):
if not path_file_Zip:
    path_file_Zip = os.path.join(
        os.path.dirname(path_dir), os.path.basename(path_dir)+'.Zip')
with zipfile.ZipFile(path_file_Zip, 'wb', zipfile.Zip_DEFLATED) as Zip_file:
    for root, dirs, files in os.walk(path_dir):
        for file_or_dir in files + dirs:
            Zip_file.write(
                os.path.join(root, file_or_dir),
                os.path.relpath(os.path.join(root, file_or_dir),
                                os.path.join(path_dir, os.path.pardir)))
0
Gürol Canbek

これが、pathlibとコンテキストマネージャを使った現代的なアプローチです。ファイルをサブフォルダーではなくZipに直接配置します。

def Zip_dir(filename: str, dir_to_Zip: pathlib.Path):
    with zipfile.ZipFile(filename, 'w', zipfile.Zip_DEFLATED) as zipf:
        # Use glob instead of iterdir(), to cover all subdirectories.
        for directory in dir_to_Zip.glob('**'):
            for file in directory.iterdir():
                if not file.is_file():
                    continue
                # Strip the first component, so we don't create an uneeded subdirectory
                # containing everything.
                Zip_path = pathlib.Path(*file.parts[1:])
                # Use a string, since zipfile doesn't support pathlib  directly.
                zipf.write(str(file), str(Zip_path))
0

さて、提案を読んだ後、私は2.7.xで "変な"ディレクトリ名(絶対的な名前)を作らずに働き、Zipの中に指定されたフォルダを作成するだけの非常によく似た方法を思いつきました。

あるいは念のため、Zipファイルに選択したディレクトリの内容を含むフォルダを含める必要がある場合もあります。

def zipDir( path, ziph ) :
 """
 Inserts directory (path) into zipfile instance (ziph)
 """
 for root, dirs, files in os.walk( path ) :
  for file in files :
   ziph.write( os.path.join( root, file ) , os.path.basename( os.path.normpath( path ) ) + "\\" + file )

def makeZip( pathToFolder ) :
 """
 Creates a Zip file with the specified folder
 """
 zipf = zipfile.ZipFile( pathToFolder + 'file.Zip', 'w', zipfile.Zip_DEFLATED )
 zipDir( pathToFolder, zipf )
 zipf.close()
 print( "Zip file saved to: " + pathToFolder)

makeZip( "c:\\path\\to\\folder\\to\\insert\\into\\zipfile" )
0
Xedret

現在のディレクトリ内のすべてのフォルダ(サブディレクトリ)を圧縮するとします。

for root, dirs, files in os.walk("."):
    for sub_dir in dirs:
        Zip_you_want = sub_dir+".Zip"
        Zip_process = zipfile.ZipFile(Zip_you_want, "w", zipfile.Zip_DEFLATED)
        Zip_process.write(file_you_want_to_include)
        Zip_process.close()

        print("Successfully zipped directory: {sub_dir}".format(sub_dir=sub_dir))
0
ShiningGo
# import required python modules
# You have to install zipfile package using pip install

import os,zipfile

# Change the directory where you want your new Zip file to be

os.chdir('Type your destination')

# Create a new zipfile ( I called it myfile )

zf = zipfile.ZipFile('myfile.Zip','w')

# os.walk gives a directory tree. Access the files using a for loop

for dirnames,folders,files in os.walk('Type your directory'):
    zf.write('Type your Directory')
    for file in files:
        zf.write(os.path.join('Type your directory',file))
0
Praveen

アーカイブする親ディレクトリの下にフォルダ階層を保持する簡潔な方法:

import glob
import zipfile

with zipfile.ZipFile(fp_Zip, "w", zipfile.Zip_DEFLATED) as zipf:
    for fp in glob(os.path.join(parent, "**/*")):
        base = os.path.commonpath([parent, fp])
        zipf.write(fp, arcname=fp.replace(base, ""))

必要に応じて、pathlibファイルグロビング用 を使用するように変更できます。

0
ryanjdillon