压缩文件并避免目录结构
zip file and avoid directory structure
我有一个 Python 压缩文件的脚本 (new.txt
):
tofile = "/root/files/result/"+file
targetzipfile = new.zip # This is how I want my zip to look like
zf = zipfile.ZipFile(targetzipfile, mode='w')
try:
#adding to archive
zf.write(tofile)
finally:
zf.close()
当我这样做时,我得到了 zip 文件。但是当我尝试解压缩文件时,我得到了一系列与文件路径相对应的目录中的文本文件,即我在 result
目录中看到一个名为 root
的文件夹以及其中的更多目录,即我有
/root/files/result/new.zip
当我解压缩 new.zip
时,我的目录结构看起来像
/root/files/result/root/files/result/new.txt
有没有一种方法可以让我在解压缩时只得到 new.txt
?
换句话说,我有 /root/files/result/new.zip
,当我解压缩 new.zip
时,它应该看起来像
/root/files/results/new.txt
zipfile.write()
方法接受一个可选的 arcname
参数,指定压缩文件中的文件名
我认为你需要对目的地做一个修改,否则会重复目录。使用 :arcname
来避免它。像这样尝试:
import os
import zipfile
def zip(src, dst):
zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED)
abs_src = os.path.abspath(src)
for dirname, subdirs, files in os.walk(src):
for filename in files:
absname = os.path.abspath(os.path.join(dirname, filename))
arcname = absname[len(abs_src) + 1:]
print 'zipping %s as %s' % (os.path.join(dirname, filename),
arcname)
zf.write(absname, arcname)
zf.close()
zip("src", "dst")
查看 Zipfile.write 的文档。
ZipFile.write(filename[, arcname[, compress_type]]) Write the file
named filename to the archive, giving it the archive name arcname (by
default, this will be the same as filename, but without a drive letter
and with leading path separators removed)
https://docs.python.org/2/library/zipfile.html#zipfile.ZipFile.write
尝试以下操作:
import zipfile
import os
filename = 'foo.txt'
# Using os.path.join is better than using '/' it is OS agnostic
path = os.path.join(os.path.sep, 'tmp', 'bar', 'baz', filename)
zip_filename = os.path.splitext(filename)[0] + '.zip'
zip_path = os.path.join(os.path.dirname(path), zip_filename)
# If you need exception handling wrap this in a try/except block
with zipfile.ZipFile(zip_path, 'w') as zf:
zf.write(path, zip_filename)
底线是,如果您不提供存档名称,则文件名将用作存档名称,它将包含文件的完整路径。
为了说明最清楚,
目录结构:
/Users
└── /user
. ├── /pixmaps
. │ ├── pixmap_00.raw
. │ ├── pixmap_01.raw
│ ├── /jpeg
│ │ ├── pixmap_00.jpg
│ │ └── pixmap_01.jpg
│ └── /png
│ ├── pixmap_00.png
│ └── pixmap_01.png
├── /docs
├── /programs
├── /misc
.
.
.
感兴趣的目录:/Users/user/pixmaps
第一次尝试
import os
import zipfile
TARGET_DIRECTORY = "/Users/user/pixmaps"
ZIPFILE_NAME = "CompressedDir.zip"
def zip_dir(directory, zipname):
"""
Compress a directory (ZIP file).
"""
if os.path.exists(directory):
outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
outZipFile.write(filepath)
outZipFile.close()
if __name__ == '__main__':
zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
ZIP 文件结构:
CompressedDir.zip
.
└── /Users
└── /user
└── /pixmaps
├── pixmap_00.raw
├── pixmap_01.raw
├── /jpeg
│ ├── pixmap_00.jpg
│ └── pixmap_01.jpg
└── /png
├── pixmap_00.png
└── pixmap_01.png
避免完整的目录路径
def zip_dir(directory, zipname):
"""
Compress a directory (ZIP file).
"""
if os.path.exists(directory):
outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
# The root directory within the ZIP file.
rootdir = os.path.basename(directory)
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
# Write the file named filename to the archive,
# giving it the archive name 'arcname'.
filepath = os.path.join(dirpath, filename)
parentpath = os.path.relpath(filepath, directory)
arcname = os.path.join(rootdir, parentpath)
outZipFile.write(filepath, arcname)
outZipFile.close()
if __name__ == '__main__':
zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
ZIP 文件结构:
CompressedDir.zip
.
└── /pixmaps
├── pixmap_00.raw
├── pixmap_01.raw
├── /jpeg
│ ├── pixmap_00.jpg
│ └── pixmap_01.jpg
└── /png
├── pixmap_00.png
└── pixmap_01.png
zf.write(tofile)
改变
zf.write(tofile, zipfile_dir)
例如
zf.write("/root/files/result/root/files/result/new.txt", "/root/files/results/new.txt")
您可以使用以下方法仅隔离源文件的文件名:
name_file_only= name_full_path.split(os.sep)[-1]
例如,如果 name_full_path
是 /root/files/results/myfile.txt
,那么 name_file_only
将是 myfile.txt
。要将 myfile.txt 压缩到存档 zf
的根目录,您可以使用:
zf.write(name_full_path, name_file_only)
我遇到了同样的问题,我用 writestr
解决了它。你可以这样使用它:
zipObject.writestr(<filename> , <file data, bytes or string>)
write 方法中的 arcname
参数指定 zip 文件中文件的名称:
import os
import zipfile
# 1. Create a zip file which we will write files to
zip_file = "/home/username/test.zip"
zipf = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
# 2. Write files found in "/home/username/files/" to the test.zip
files_to_zip = "/home/username/files/"
for file_to_zip in os.listdir(files_to_zip):
file_to_zip_full_path = os.path.join(files_to_zip, file_to_zip)
# arcname argument specifies what will be the name of the file inside the zipfile
zipf.write(filename=file_to_zip_full_path, arcname=file_to_zip)
zipf.close()
我们可以用这个
import os
# single File
os.system(f"cd {destinationFolder} && zip fname.zip fname")
# directory
os.system(f"cd {destinationFolder} && zip -r folder.zip folder")
对我来说,这很管用。
如果你想要一种优雅的方式来使用 pathlib
你可以这样使用它:
from pathlib import Path
import zipfile
def zip_dir(path_to_zip: Path):
zip_file = Path(path_to_zip).with_suffix('.zip')
z = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
for f in list(path_to_zip.rglob('*.*')):
z.write(f, arcname=f.relative_to(path_to_zip))
比预期的要简单得多,我使用参数“arcname”配置模块为“file_to_be_zipped.txt”,所以文件夹没有出现在我的最终压缩文件中:
mmpk_zip_file = zipfile.ZipFile("c:\Destination_folder_name\newzippedfilename.zip", mode='w', compression=zipfile.ZIP_DEFLATED)
mmpk_zip_file.write("c:\Source_folder_name\file_to_be_zipped.txt", "file_to_be_zipped.txt")
mmpk_zip_file.close()
为了摆脱绝对路径,我想到了这个:
def create_zip(root_path, file_name, ignored=[], storage_path=None):
"""Create a ZIP
This function creates a ZIP file of the provided root path.
Args:
root_path (str): Root path to start from when picking files and directories.
file_name (str): File name to save the created ZIP file as.
ignored (list): A list of files and/or directories that you want to ignore. This
selection is applied in root directory only.
storage_path: If provided, ZIP file will be placed in this location. If None, the
ZIP will be created in root_path
"""
if storage_path is not None:
zip_root = os.path.join(storage_path, file_name)
else:
zip_root = os.path.join(root_path, file_name)
zipf = zipfile.ZipFile(zip_root, 'w', zipfile.ZIP_DEFLATED)
def iter_subtree(path, layer=0):
# iter the directory
path = Path(path)
for p in path.iterdir():
if layer == 0 and p.name in ignored:
continue
zipf.write(p, str(p).replace(root_path, '').lstrip('/'))
if p.is_dir():
iter_subtree(p, layer=layer+1)
iter_subtree(root_path)
zipf.close()
也许这不是最优雅的解决方案,但它确实有效。如果我们在向 write()
方法提供文件名时只使用 p.name
,那么它不会创建正确的目录结构。
此外,如果需要忽略根路径中选定的目录或文件,这也会忽略这些选择。
指定write方法的arcname输入如下:
tofile = "/root/files/result/"+file
NewRoot = "files/result/"
zf.write(tofile, arcname=tofile.split(NewRoot)[1])
更多信息:
ZipFile.write(filename, arcname=None, compress_type=None,
compresslevel=None)
https://docs.python.org/3/library/zipfile.html
我有一个 Python 压缩文件的脚本 (new.txt
):
tofile = "/root/files/result/"+file
targetzipfile = new.zip # This is how I want my zip to look like
zf = zipfile.ZipFile(targetzipfile, mode='w')
try:
#adding to archive
zf.write(tofile)
finally:
zf.close()
当我这样做时,我得到了 zip 文件。但是当我尝试解压缩文件时,我得到了一系列与文件路径相对应的目录中的文本文件,即我在 result
目录中看到一个名为 root
的文件夹以及其中的更多目录,即我有
/root/files/result/new.zip
当我解压缩 new.zip
时,我的目录结构看起来像
/root/files/result/root/files/result/new.txt
有没有一种方法可以让我在解压缩时只得到 new.txt
?
换句话说,我有 /root/files/result/new.zip
,当我解压缩 new.zip
时,它应该看起来像
/root/files/results/new.txt
zipfile.write()
方法接受一个可选的 arcname
参数,指定压缩文件中的文件名
我认为你需要对目的地做一个修改,否则会重复目录。使用 :arcname
来避免它。像这样尝试:
import os
import zipfile
def zip(src, dst):
zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED)
abs_src = os.path.abspath(src)
for dirname, subdirs, files in os.walk(src):
for filename in files:
absname = os.path.abspath(os.path.join(dirname, filename))
arcname = absname[len(abs_src) + 1:]
print 'zipping %s as %s' % (os.path.join(dirname, filename),
arcname)
zf.write(absname, arcname)
zf.close()
zip("src", "dst")
查看 Zipfile.write 的文档。
ZipFile.write(filename[, arcname[, compress_type]]) Write the file named filename to the archive, giving it the archive name arcname (by default, this will be the same as filename, but without a drive letter and with leading path separators removed)
https://docs.python.org/2/library/zipfile.html#zipfile.ZipFile.write
尝试以下操作:
import zipfile
import os
filename = 'foo.txt'
# Using os.path.join is better than using '/' it is OS agnostic
path = os.path.join(os.path.sep, 'tmp', 'bar', 'baz', filename)
zip_filename = os.path.splitext(filename)[0] + '.zip'
zip_path = os.path.join(os.path.dirname(path), zip_filename)
# If you need exception handling wrap this in a try/except block
with zipfile.ZipFile(zip_path, 'w') as zf:
zf.write(path, zip_filename)
底线是,如果您不提供存档名称,则文件名将用作存档名称,它将包含文件的完整路径。
为了说明最清楚,
目录结构:
/Users
└── /user
. ├── /pixmaps
. │ ├── pixmap_00.raw
. │ ├── pixmap_01.raw
│ ├── /jpeg
│ │ ├── pixmap_00.jpg
│ │ └── pixmap_01.jpg
│ └── /png
│ ├── pixmap_00.png
│ └── pixmap_01.png
├── /docs
├── /programs
├── /misc
.
.
.
感兴趣的目录:/Users/user/pixmaps
第一次尝试
import os
import zipfile
TARGET_DIRECTORY = "/Users/user/pixmaps"
ZIPFILE_NAME = "CompressedDir.zip"
def zip_dir(directory, zipname):
"""
Compress a directory (ZIP file).
"""
if os.path.exists(directory):
outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
outZipFile.write(filepath)
outZipFile.close()
if __name__ == '__main__':
zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
ZIP 文件结构:
CompressedDir.zip
.
└── /Users
└── /user
└── /pixmaps
├── pixmap_00.raw
├── pixmap_01.raw
├── /jpeg
│ ├── pixmap_00.jpg
│ └── pixmap_01.jpg
└── /png
├── pixmap_00.png
└── pixmap_01.png
避免完整的目录路径
def zip_dir(directory, zipname):
"""
Compress a directory (ZIP file).
"""
if os.path.exists(directory):
outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
# The root directory within the ZIP file.
rootdir = os.path.basename(directory)
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
# Write the file named filename to the archive,
# giving it the archive name 'arcname'.
filepath = os.path.join(dirpath, filename)
parentpath = os.path.relpath(filepath, directory)
arcname = os.path.join(rootdir, parentpath)
outZipFile.write(filepath, arcname)
outZipFile.close()
if __name__ == '__main__':
zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
ZIP 文件结构:
CompressedDir.zip
.
└── /pixmaps
├── pixmap_00.raw
├── pixmap_01.raw
├── /jpeg
│ ├── pixmap_00.jpg
│ └── pixmap_01.jpg
└── /png
├── pixmap_00.png
└── pixmap_01.png
zf.write(tofile)
改变
zf.write(tofile, zipfile_dir)
例如
zf.write("/root/files/result/root/files/result/new.txt", "/root/files/results/new.txt")
您可以使用以下方法仅隔离源文件的文件名:
name_file_only= name_full_path.split(os.sep)[-1]
例如,如果 name_full_path
是 /root/files/results/myfile.txt
,那么 name_file_only
将是 myfile.txt
。要将 myfile.txt 压缩到存档 zf
的根目录,您可以使用:
zf.write(name_full_path, name_file_only)
我遇到了同样的问题,我用 writestr
解决了它。你可以这样使用它:
zipObject.writestr(<filename> , <file data, bytes or string>)
write 方法中的 arcname
参数指定 zip 文件中文件的名称:
import os
import zipfile
# 1. Create a zip file which we will write files to
zip_file = "/home/username/test.zip"
zipf = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
# 2. Write files found in "/home/username/files/" to the test.zip
files_to_zip = "/home/username/files/"
for file_to_zip in os.listdir(files_to_zip):
file_to_zip_full_path = os.path.join(files_to_zip, file_to_zip)
# arcname argument specifies what will be the name of the file inside the zipfile
zipf.write(filename=file_to_zip_full_path, arcname=file_to_zip)
zipf.close()
我们可以用这个
import os
# single File
os.system(f"cd {destinationFolder} && zip fname.zip fname")
# directory
os.system(f"cd {destinationFolder} && zip -r folder.zip folder")
对我来说,这很管用。
如果你想要一种优雅的方式来使用 pathlib
你可以这样使用它:
from pathlib import Path
import zipfile
def zip_dir(path_to_zip: Path):
zip_file = Path(path_to_zip).with_suffix('.zip')
z = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
for f in list(path_to_zip.rglob('*.*')):
z.write(f, arcname=f.relative_to(path_to_zip))
比预期的要简单得多,我使用参数“arcname”配置模块为“file_to_be_zipped.txt”,所以文件夹没有出现在我的最终压缩文件中:
mmpk_zip_file = zipfile.ZipFile("c:\Destination_folder_name\newzippedfilename.zip", mode='w', compression=zipfile.ZIP_DEFLATED)
mmpk_zip_file.write("c:\Source_folder_name\file_to_be_zipped.txt", "file_to_be_zipped.txt")
mmpk_zip_file.close()
为了摆脱绝对路径,我想到了这个:
def create_zip(root_path, file_name, ignored=[], storage_path=None):
"""Create a ZIP
This function creates a ZIP file of the provided root path.
Args:
root_path (str): Root path to start from when picking files and directories.
file_name (str): File name to save the created ZIP file as.
ignored (list): A list of files and/or directories that you want to ignore. This
selection is applied in root directory only.
storage_path: If provided, ZIP file will be placed in this location. If None, the
ZIP will be created in root_path
"""
if storage_path is not None:
zip_root = os.path.join(storage_path, file_name)
else:
zip_root = os.path.join(root_path, file_name)
zipf = zipfile.ZipFile(zip_root, 'w', zipfile.ZIP_DEFLATED)
def iter_subtree(path, layer=0):
# iter the directory
path = Path(path)
for p in path.iterdir():
if layer == 0 and p.name in ignored:
continue
zipf.write(p, str(p).replace(root_path, '').lstrip('/'))
if p.is_dir():
iter_subtree(p, layer=layer+1)
iter_subtree(root_path)
zipf.close()
也许这不是最优雅的解决方案,但它确实有效。如果我们在向 write()
方法提供文件名时只使用 p.name
,那么它不会创建正确的目录结构。
此外,如果需要忽略根路径中选定的目录或文件,这也会忽略这些选择。
指定write方法的arcname输入如下:
tofile = "/root/files/result/"+file
NewRoot = "files/result/"
zf.write(tofile, arcname=tofile.split(NewRoot)[1])
更多信息:
ZipFile.write(filename, arcname=None, compress_type=None, compresslevel=None) https://docs.python.org/3/library/zipfile.html