Câu trả lời:
Như những người khác đã chỉ ra, bạn nên sử dụng zipfile . Tài liệu cho bạn biết những chức năng nào có sẵn, nhưng không thực sự giải thích cách bạn có thể sử dụng chúng để nén toàn bộ thư mục. Tôi nghĩ rằng nó dễ nhất để giải thích với một số mã ví dụ:
#!/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()
Chuyển thể từ: http://www.devshed.com/c/a/Python/Python-UnZipped/
os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))
. Điều đó sẽ cho phép bạn nén một thư mục từ bất kỳ thư mục làm việc nào, mà không nhận được các đường dẫn tuyệt đối đầy đủ trong kho lưu trữ.
shutil
làm cho nó thực sự dễ dàng chỉ trong một dòng duy nhất. Vui lòng kiểm tra câu trả lời bên dưới ..
.close()
cuộc gọi!
Cách dễ nhất là sử dụng shutil.make_archive
. Nó hỗ trợ cả định dạng zip và tar.
import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
Nếu bạn cần phải làm một cái gì đó phức tạp hơn là nén toàn bộ thư mục (chẳng hạn như bỏ qua một số tệp nhất định), thì bạn sẽ cần phải đào sâu vào zipfile
mô-đun như những người khác đã đề xuất.
shutil
là một phần của thư viện python tiêu chuẩn. Đây phải là câu trả lời hàng đầu
shutil.make_archive
sử dụng đó os.chdir()
. Từ những gì tôi đang đọc os.chdir()
, nó hoạt động trên toàn cầu.
Để thêm nội dung của mydirectory
tệp zip mới, bao gồm tất cả các tệp và thư mục con:
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()
with
thay vì phải gọi close()
cho mình vào cuối?
Làm cách nào tôi có thể tạo một kho lưu trữ zip của cấu trúc thư mục trong Python?
Trong Python 2.7+, shutil
có một make_archive
chức năng.
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
Ở đây kho lưu trữ nén sẽ được đặt tên zipfile_name.zip
. Nếu base_dir
ở xa hơn root_dir
nó sẽ loại trừ các tệp không có trong base_dir
, nhưng vẫn lưu trữ các tệp trong thư mục gốc lên đến root_dir
.
Tôi đã có một vấn đề kiểm tra điều này trên Cygwin với 2.7 - nó muốn có một đối số root_dir, cho cwd:
make_archive('zipfile_name', 'zip', root_dir='.')
Bạn cũng có thể làm điều này với Python từ trình bao bằng cách sử dụng zipfile
mô-đun:
$ python -m zipfile -c zipname sourcedir
Trong trường hợp zipname
là tên của tập tin đích bạn muốn (thêm .zip
nếu bạn muốn nó, nó sẽ không làm điều đó tự động) và SourceDir là đường dẫn đến thư mục.
Nếu bạn đang cố gắng nén một gói python bằng một __init__.py
và __main__.py
, và bạn không muốn thư mục gốc, thì đó là
$ python -m zipfile -c zipname sourcedir/*
Và
$ python zipname
sẽ chạy gói. (Lưu ý rằng bạn không thể chạy các gói con làm điểm vào từ kho lưu trữ được nén.)
Nếu bạn có python3.5 + và đặc biệt muốn nén gói Python, hãy sử dụng zipapp :
$ python -m zipapp myapp
$ python myapp.pyz
Hàm này sẽ nén đệ quy một cây thư mục, nén các tệp và ghi lại tên tệp tương đối chính xác trong kho lưu trữ. Các mục lưu trữ giống như các mục được tạo bởi 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)
Sử dụng shutil, một phần của bộ thư viện chuẩn python. Sử dụng shutil rất đơn giản (xem mã bên dưới):
Mã số:
import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
Để thêm nén vào tệp zip kết quả, hãy kiểm tra liên kết này .
Bạn cần thay đổi:
zip = zipfile.ZipFile('Python.zip', 'w')
đến
zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
Tôi đã thực hiện một số thay đổi đối với mã do Mark Byers đưa ra . Chức năng bên dưới cũng sẽ thêm các thư mục trống nếu bạn có chúng. Các ví dụ sẽ làm rõ hơn đường dẫn được thêm vào zip là gì.
#!/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)
Trên đây là một chức năng đơn giản nên làm việc cho các trường hợp đơn giản. Bạn có thể tìm thấy lớp thanh lịch hơn trong Gist của tôi: https://gist.github.com/Eccenux/17526123107ca0ac28e6
Python hiện đại (3.6+) bằng cách sử dụng pathlib
mô-đun để xử lý các đường dẫn giống như OOP và pathlib.Path.rglob()
để tạo vòng lặp đệ quy. Theo như tôi có thể nói, điều này tương đương với câu trả lời của George V. Reilly: khóa có nén, phần tử trên cùng là một thư mục, giữ các thư mục trống, sử dụng các đường dẫn tương đối.
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))
Lưu ý: như gợi ý loại tùy chọn chỉ ra, zip_name
không thể là đối tượng Đường dẫn ( sẽ được sửa trong 3.6.2+ ).
Tôi có một ví dụ mã khác có thể giúp đỡ, sử dụng python3, pathlib và zipfile. Nó nên hoạt động trong bất kỳ hệ điều hành.
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!')
Bạn có thể muốn nhìn vào zipfile
mô-đun; có tài liệu tại http://docs.python.org/l Library / zipfile.html .
Bạn cũng có thể muốn os.walk()
lập chỉ mục cấu trúc thư mục.
Đây là một biến thể về câu trả lời được đưa ra bởi Nux phù hợp với tôi:
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 )
Hãy thử một cái dưới đây. Nó làm việc cho tôi .
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()
Nếu bạn muốn một chức năng như thư mục nén của bất kỳ trình quản lý tệp đồ họa phổ biến nào, bạn có thể sử dụng mã sau đây, nó sử dụng mô-đun zipfile . Sử dụng mã này, bạn sẽ có tệp zip với đường dẫn là thư mục gốc của nó.
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()
Để linh hoạt hơn, ví dụ: chọn thư mục / tệp theo tên sử dụng:
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
Đối với cây tập tin:
.
├── dir
│ ├── dir2
│ │ └── file2.txt
│ ├── dir3
│ │ └── file3.txt
│ └── file.txt
├── dir4
│ ├── dir5
│ └── file4.txt
├── listdir.zip
├── main.py
├── root.txt
└── selective.zip
Bạn có thể chọn, ví dụ chỉ chọn dir4
và 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)
Hoặc chỉ listdir
trong thư mục gọi tập lệnh và thêm mọi thứ từ đó:
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)
Giả sử bạn muốn Zip tất cả các thư mục (thư mục con) trong thư mục hiện tại.
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))
Đối với một cách ngắn gọn để giữ lại hệ thống phân cấp thư mục trong thư mục mẹ sẽ được lưu trữ:
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, ""))
Nếu bạn muốn, bạn có thể thay đổi điều này để sử dụng pathlib
cho tập tin toàn cầu .
Rất nhiều câu trả lời ở đây và tôi hy vọng tôi có thể đóng góp với phiên bản của riêng mình, dựa trên câu trả lời ban đầu (nhân tiện), nhưng với góc nhìn đồ họa nhiều hơn, cũng sử dụng bối cảnh cho mỗi zipfile
thiết lập và sắp xếpos.walk()
, để có một sản lượng đặt hàng.
Có các thư mục này và chúng là các tệp (trong số các thư mục khác), tôi muốn tạo một thư mục .zip
cho mỗi cap_
thư mục:
$ tree -d
.
├── cap_01
| ├── 0101000001.json
| ├── 0101000002.json
| ├── 0101000003.json
|
├── cap_02
| ├── 0201000001.json
| ├── 0201000002.json
| ├── 0201001003.json
|
├── cap_03
| ├── 0301000001.json
| ├── 0301000002.json
| ├── 0301000003.json
|
├── docs
| ├── map.txt
| ├── main_data.xml
|
├── core_files
├── core_master
├── core_slave
Đây là những gì tôi đã áp dụng, với các ý kiến để hiểu rõ hơn về quy trình.
$ cat zip_cap_dirs.py
""" Zip 'cap_*' directories. """
import os
import zipfile as zf
for root, dirs, files in sorted(os.walk('.')):
if 'cap_' in root:
print(f"Compressing: {root}")
# Defining .zip name, according to Capítulo.
cap_dir_zip = '{}.zip'.format(root)
# Opening zipfile context for current root dir.
with zf.ZipFile(cap_dir_zip, 'w', zf.ZIP_DEFLATED) as new_zip:
# Iterating over os.walk list of files for the current root dir.
for f in files:
# Defining relative path to files from current root dir.
f_path = os.path.join(root, f)
# Writing the file on the .zip file of the context
new_zip.write(f_path)
Về cơ bản, với mỗi lần lặp lại os.walk(path)
, tôi đang mở một bối cảnh để zipfile
thiết lập và sau đó, lặp đi lặp lại files
, đó là một list
tệp từ root
thư mục, tạo thành đường dẫn tương đối cho mỗi tệp dựa trên root
thư mục hiện tại , nối vàozipfile
bối cảnh đang chạy .
Và đầu ra được trình bày như thế này:
$ python3 zip_cap_dirs.py
Compressing: ./cap_01
Compressing: ./cap_02
Compressing: ./cap_03
Để xem nội dung của từng .zip
thư mục, bạn có thể sử dụng less
lệnh:
$ less cap_01.zip
Archive: cap_01.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
22017 Defl:N 2471 89% 2019-09-05 08:05 7a3b5ec6 cap_01/0101000001.json
21998 Defl:N 2471 89% 2019-09-05 08:05 155bece7 cap_01/0101000002.json
23236 Defl:N 2573 89% 2019-09-05 08:05 55fced20 cap_01/0101000003.json
-------- ------- --- -------
67251 7515 89% 3 files
Đây là một cách tiếp cận hiện đại, sử dụng pathlib và trình quản lý bối cảnh. Đặt các tệp trực tiếp trong zip, thay vì trong thư mục con.
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))
Tôi đã chuẩn bị một chức năng bằng cách hợp nhất giải pháp của Mark Byers với các bình luận của Reimund và Morten Zilmer (đường dẫn tương đối và bao gồm các thư mục trống). Như một thực hành tốt nhất,with
được sử dụng trong xây dựng tệp của ZipFile.
Hàm này cũng chuẩn bị một tên tệp zip mặc định với tên thư mục được nén và phần mở rộng '.zip'. Do đó, nó chỉ hoạt động với một đối số: thư mục nguồn được nén.
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)))
# 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))
Chà, sau khi đọc các gợi ý, tôi đã nghĩ ra một cách rất giống với 2.7.x mà không tạo tên thư mục "buồn cười" (tên giống như tuyệt đối), và sẽ chỉ tạo thư mục được chỉ định bên trong zip.
Hoặc chỉ trong trường hợp bạn cần zip của bạn để chứa một thư mục bên trong với nội dung của thư mục đã chọn.
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" )
Chức năng tạo tập tin 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()
make_archive
từshutil
(nếu bạn muốn nén một thư mục theo cách đệ quy).