Python でディレクトリ構造の zip アーカイブを作成するにはどうすればよいですか?
27 に答える
最も簡単な方法は、 を使用することshutil.make_archive
です。zip 形式と tar 形式の両方をサポートしています。
import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
zipfile
ディレクトリ全体を圧縮するよりも複雑なことをする必要がある場合 (特定のファイルをスキップするなど)、他の人が提案したようにモジュールを掘り下げる必要があります。
他の人が指摘したように、zipfileを使用する必要があります。ドキュメントには、利用可能な機能が記載されていますが、それらを使用してディレクトリ全体を圧縮する方法については実際には説明されていません。いくつかのサンプルコードで説明するのが最も簡単だと思います:
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),
os.path.relpath(os.path.join(root, file),
os.path.join(path, '..')))
zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
zipdir('tmp/', zipf)
zipf.close()
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()
Python でディレクトリ構造の zip アーカイブを作成するにはどうすればよいですか?
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 でこれをテストする際に問題がありました。cwd の root_dir 引数が必要です。
make_archive('zipfile_name', 'zip', root_dir='.')
シェルからの Python の使用
zipfile
モジュールを使用して、シェルからPythonでこれを行うことができます:
$ python -m zipfile -c zipname sourcedir
wherezipname
は目的の宛先ファイルの名前 (必要に応じて追加.zip
しますが、自動的には追加されません) であり、sourcedir はディレクトリへのパスです。
Python を圧縮する (または単に親ディレクトリを必要としない):
と を使用して python パッケージを圧縮しようとして__init__.py
い__main__.py
て、親ディレクトリが必要ない場合は、
$ python -m zipfile -c zipname sourcedir/*
と
$ python zipname
パッケージを実行します。(zip アーカイブからのエントリ ポイントとしてサブパッケージを実行できないことに注意してください。)
Python アプリの圧縮:
Python3.5+ を使用していて、特に Python パッケージを圧縮したい場合は、 zipapp を使用します。
$ python -m zipapp myapp
$ python myapp.pyz
Python 標準ライブラリ セットの一部である shutil を使用します。shutil の使用はとても簡単です (以下のコードを参照):
- 第 1 引数: 結果の zip/tar ファイルのファイル名、
- 2 番目の引数: zip/tar、
- 3 番目の引数: dir_name
コード:
import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
結果の zip ファイルに圧縮を追加するには、このリンクを確認してください。
変更する必要があります:
zip = zipfile.ZipFile('Python.zip', 'w')
に
zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
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)
上記は、単純なケースで機能する単純な関数です。私のGistでよりエレガントなクラスを見つけることができます: https://gist.github.com/Eccenux/17526123107ca0ac28e6
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 __name__ == '__main__':
zip_dir('.')
print('end!')
一般的なグラフィカル ファイル マネージャーの圧縮フォルダーのような機能が必要な場合は、次のコードを使用できます。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()
zipfile
おそらくモジュールを見たいと思うでしょう。http://docs.python.org/library/zipfile.htmlにドキュメントがあります。
os.walk()
ディレクトリ構造のインデックスを作成することもできます。
これは、私にとって有効な 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 )
以下のものを試してみてください。
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()
柔軟性を高めるには、たとえば、名前を使用してディレクトリ/ファイルを選択します。
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
dir4
たとえば、 と のみを選択できますroot.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)
これは、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))
Reimund と Morten Zilmer のコメント (相対パスと空のディレクトリを含む) を使用して、Mark Byers のソリューションを統合した関数を用意しました。ベスト プラクティスとして、with
ZipFile のファイル構成で使用されます。
この関数は、zip されたディレクトリ名と「.zip」拡張子を持つデフォルトの zip ファイル名も準備します。したがって、1 つの引数のみで動作します: zip されるソース ディレクトリです。
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)))