كيفية إنشاء أرشيف الرمز البريدي في دليل في بيثون؟
-
13-09-2019 - |
سؤال
كيف يمكنني إنشاء أرشيف مضغوط لهيكل الدليل في بيثون؟
المحلول
كما أشار آخرون، يجب عليك استخدام ملف مضغوط. وبعد تخبرك الوثائق بوظائف متوفرة، ولكن لا تفسر حقا كيف يمكنك استخدامها لزود الدليل بأكمله. أعتقد أنه من الأسهل تشرح برمز بعض الأمثلة:
#!/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-unzpecip/
نصائح أخرى
أسهل طريقة هي استخدام shutil.make_archive
. وبعد وهو يدعم صيغ الرمز البريدي والرقار.
import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
إذا كنت بحاجة إلى القيام بشيء أكثر تعقيدا من تقليص الدليل بأكمله (مثل تخطي بعض الملفات)، فستحتاج إلى حفر إلى zipfile
الوحدة كما اقترح الآخرون.
لإضافة محتويات mydirectory
إلى ملف مضغوط جديد، بما في ذلك جميع الملفات والدلائل الفرعية:
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()
كيف يمكنني إنشاء أرشيف مضغوط لهيكل الدليل في بيثون؟
في البرنامج النصي بيثون
في بيثون 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 من قذيفة أيضا باستخدام zipfile
وحدة:
$ python -m zipfile -c zipname sourcedir
أين zipname
هل اسم الملف الوجهة الذي تريده (إضافة .zip
إذا كنت تريد ذلك، فلن يقوم بذلك تلقائيا) و Sourcedir هو المسار إلى الدليل.
Zipping Up Python (أو فقط لا تريد الوالد Dir):
إذا كنت تحاول تشغيل حزمة بيثون مع __init__.py
و __main__.py
, ، وأنت لا تريد الوالد دير، إنه
$ python -m zipfile -c zipname sourcedir/*
و
$ python zipname
سوف تشغيل الحزمة. (لاحظ أنه لا يمكنك تشغيل subpackages كأداة الدخول من الأرشيف المضغوط.)
Zipping تطبيق Python:
إذا كان لديك Python3.5 +، وتريد خصيصا لتعمدي حزمة بيثون، استخدم شطر:
$ python -m zipapp myapp
$ python myapp.pyz
هذه الوظيفة ستقدم بشكل متكرر فوق شجرة الدليل، ضغط الملفات وتسجيل أسماء الملفات النسبية الصحيحة في الأرشيف. إدخالات الأرشيف هي نفسها تلك التي تم إنشاؤها 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)
استخدم Shutil، وهو جزء من مجموعة مكتبة Python القياسية. باستخدام Shutil بسيط جدا (انظر التعليمات البرمجية أدناه):
- arg 1st: اسم ملف zip / القطران الناتج،
- 2nd Arg: Zip / Tar،
- 3rd Arg: 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)
لقد اتخذت بعض التغييرات الرمز الذي قدمه مارك byers. وبعد ستضيف الوظيفة أدناه أيضا دلائل فارغة إذا كان لديك لهم. يجب أن تجعل الأمثلة أكثر وضوحا ما يضاف المسار إلى الرمز البريدي.
#!/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.
ربما تريد أن تنظر إلى zipfile
وحدة؛ هناك وثائق في http://docs.python.org/library/zipfile.html..
قد تريد أيضا os.walk()
لفهرسة بنية الدليل.
لدي مثال رمز آخر قد يساعد، باستخدام 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!')
فيما يلي اختلاف في الإجابة المقدمة من 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 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()
بيثون الحديثة (3.6+) باستخدام pathlib
الوحدة النمطية للتعامل مع مسارات موجزة من المسارات، و pathlib.Path.rglob()
لتكريم العالم. بقدر ما أستطيع أن أقول، هذا يعادل إجابة جورج خامسا.
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
لا يمكن أن يكون كائن المسار (سيتم إصلاحه في 3.6.2+).
لإعطاء المزيد من المرونة، مثل تحديد الدليل / الملف حسب استخدام الاسم:
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)
قل أنك تريد مضغوط جميع المجلدات (الدلائل الفرعية) في الدليل الحالي.
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))
إليك نهج حديث، باستخدام Pathlib، ومدير سياق. يضع الملفات مباشرة في الرمز البريدي، بدلا من مجلد فرعي.
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))
أعددت وظيفة من خلال دمج حل مارك Byers مع تعليقات Reimund ومورتن Zilmer (المسار النسبي بما في ذلك الدلائل الفارغة). كأفضل الممارسات، with
يستخدم في بناء ملف zipfile.
تقوم الوظيفة أيضا بإعداد اسم ملف مضغوط افتراضي مع اسم الدليل المضغوط وملحق ".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)))
# 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))
حسنا، بعد قراءة الاقتراحات التي جئت بطريقة مشابهة للغاية تعمل مع 2.7.x دون إنشاء أسماء دليل "مضحك" (الأسماء المطلقة مثل)، ولن أقوم فقط بإنشاء المجلد المحدد داخل الرمز البريدي.
أو فقط في حالة احتاج الرمز البريدي الخاص بك لاحتواء مجلد في الداخل باستخدام محتويات الدليل المحدد.
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" )
وظيفة لإنشاء ملف مضغوط.
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()
للحصول على طريقة موجزة للحفاظ على التسلسل الهرمي للمجلد في إطار الدليل الأصل الذي سيتم أرشفه:
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
لملف globbing..
الكثير من الإجابات هنا، وآمل أن أسهم في الإصدار الخاص بي، الذي يعتمد على الإجابة الأصلية (بالمناسبة)، ولكن مع وجود منظور رسومي أكثر، أيضا باستخدام السياق لكل منهما zipfile
الإعداد والفرز os.walk()
, ، من أجل الحصول على إخراج أمر.
وجود هذه المجلدات وملفاتهم (من بين مجلدات أخرى)، أردت إنشاء .zip
لكل شيء cap_
مجلد:
$ 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
إليك ما تقدمت به، مع تعليقات لفهم أفضل للعملية.
$ 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)
أساسا، لكل تكرار os.walk(path)
, ، أنا أفتح سياقا zipfile
الإعداد وبعد ذلك، تكرار التكرار files
, ، وهو list
من الملفات من root
الدليل، تشكيل المسار النسبي لكل ملف بناء على الحالي root
الدليل، إلحاق zipfile
السياق الذي يعمل.
ويتم عرض الإخراج مثل هذا:
$ python3 zip_cap_dirs.py
Compressing: ./cap_01
Compressing: ./cap_02
Compressing: ./cap_03
لرؤية محتويات كل منهما .zip
الدليل، يمكنك استخدام less
أمر:
$ 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