如何消除绝对路径的压缩档案文件,如果绝对路径提供?

我有两个文件在两个不同的目录,一个是 '/home/test/first/first.pdf',另一个是 '/home/text/second/second.pdf'。我使用以下代码来压缩它们:

import zipfile, StringIO
buffer = StringIO.StringIO()
first_path = '/home/test/first/first.pdf'
second_path = '/home/text/second/second.pdf'
zip = zipfile.ZipFile(buffer, 'w')
zip.write(first_path)
zip.write(second_path)
zip.close()

打开我创建的 zip 文件后,我在其中有一个 home文件夹,然后有两个子文件夹,firstsecond,然后是 pdf 文件。我不知道如何包括只有两个 pdf 文件,而不是有完整的路径压缩到压缩文件。我希望我把我的问题说清楚,请帮助。

68344 次浏览

I suspect there might be a more elegant solution, but this one should work:

def add_zip_flat(zip, filename):
dir, base_filename = os.path.split(filename)
os.chdir(dir)
zip.write(base_filename)


zip = zipfile.ZipFile(buffer, 'w')
add_zip_flat(zip, first_path)
add_zip_flat(zip, second_path)
zip.close()

The zipfile write() method supports an extra argument (arcname) which is the archive name to be stored in the zip file, so you would only need to change your code with:

from os.path import basename
...
zip.write(first_path, basename(first_path))
zip.write(second_path, basename(second_path))
zip.close()

When you have some spare time reading the documentation for zipfile will be helpful.

I use this function to zip a directory without include absolute path

import zipfile
import os
def zipDir(dirPath, zipPath):
zipf = zipfile.ZipFile(zipPath , mode='w')
lenDirPath = len(dirPath)
for root, _ , files in os.walk(dirPath):
for file in files:
filePath = os.path.join(root, file)
zipf.write(filePath , filePath[lenDirPath :] )
zipf.close()
#end zipDir

Can be done that way also (this allow for creating archives >2GB)

import os, zipfile
def zipdir(path, ziph):
"""zipper"""
for root, _, files in os.walk(path):
for file_found in files:
abs_path = root+'/'+file_found
ziph.write(abs_path, file_found)
zipf = zipfile.ZipFile(DEST_FILE.zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True)
zipdir(SOURCE_DIR, zipf)
zipf.close()

You can override the filename in the archive with the arcname parameter:

with zipfile.ZipFile(file="sample.zip", mode="w", compression=zipfile.ZIP_DEFLATED) as out_zip:
for f in Path.home().glob("**/*.txt"):
out_zip.write(f, arcname=f.name)

Documentation reference: https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile.write

As João Pinto said, the arcname argument of ZipFile.write is what you need. Also, reading the documentation of pathlib is helpful. You can easily get the relative path to something also with pathlib.Path.relative_to, no need to switch to os.path.

import zipfile
from pathlib import Path


folder_to_compress = Path("/path/to/folder")
path_to_archive = Path("/path/to/archive.zip")


with zipfile.ZipFile(
path_to_archive,
mode="w",
compression=zipfile.ZIP_DEFLATED,
compresslevel=7,
) as zip:
for file in folder_to_compress.rglob("*"):
relative_path = file.relative_to(folder_to_compress)
print(f"Packing {file} as {relative_path}")
zip.write(file, arcname=relative_path)