如何在提供文件的绝对路径的情况下消除zip归档中的绝对路径?

103

我有两个不同目录下的文件,一个是'/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文件而不是将完整路径压缩到zip归档中。我希望我的问题清楚明了,请帮忙。

6个回答

206

zipfile的write()方法支持一个额外的参数(arcname),用于指定存储在zip文件中的归档名称,因此您只需要将代码更改为:

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

当你有一些空闲时间时,阅读zipfile的文档会很有帮助。


如果我想将自定义文件夹名称添加到zip文件中,然后在该文件夹中放置最终文件,我该怎么做? - Debdut Goswami
如果您正在使用 pathlib 处理文件路径,您可以使用 first_path.name。https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.name - rubick

17

我使用这个函数来压缩一个目录,但不包含绝对路径

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

5
我怀疑可能有更优雅的解决方案,但这个应该可以工作:
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()

5

您可以使用 arcname 参数来覆盖存档中的文件名:

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)

文档参考:https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile.write

(该文档为Python官方文档,介绍了ZipFile库中的write()函数)

1
正如João Pinto所说,ZipFile.write的arcname参数是您需要的。另外,阅读pathlib的文档也很有帮助。您可以使用pathlib.Path.relative_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)

1

也可以这样做(这样可以创建大于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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接