如何使用Python(版本2.5)压缩文件夹中的内容?

28

当我在特定文件夹中收集到所有需要的文件后,希望我的Python脚本可以将文件夹内容压缩成zip格式。

这个是否可能实现?

如果可以,我应该怎样做呢?


现代Python的答案在这里 - Russia Must Remove Putin
4个回答

42

32

修改后的脚本如下:

#!/usr/bin/env python
from __future__ import with_statement
from contextlib import closing
from zipfile import ZipFile, ZIP_DEFLATED
import os

def zipdir(basedir, archivename):
    assert os.path.isdir(basedir)
    with closing(ZipFile(archivename, "w", ZIP_DEFLATED)) as z:
        for root, dirs, files in os.walk(basedir):
            #NOTE: ignore empty directories
            for fn in files:
                absfn = os.path.join(root, fn)
                zfn = absfn[len(basedir)+len(os.sep):] #XXX: relative path
                z.write(absfn, zfn)

if __name__ == '__main__':
    import sys
    basedir = sys.argv[1]
    archivename = sys.argv[2]
    zipdir(basedir, archivename)

示例:

C:\zipdir> python -mzipdir c:\tmp\test test.zip

它创建了名为'C:\zipdir\test.zip'的压缩文件,其中包含'c:\tmp\test'目录的内容。

为什么不使用absbasedir=os.path.abspath(basedir); os.path.relpath(absfn,absbasedir)呢?另外,basediros.sep的长度可以视为常量,因此应该在两个循环之外。 - n611x007
以前从未听说过contextlib.closing,但它使with语句与2.5向后兼容。 以前我曾遇到错误...“with [statement] from future”;),因为一些stdlib函数不支持2.5中的with(即使语句本身在导入时可以工作),而在2.7中支持它。 我想这可以通过使用closing来避免。 - n611x007
我使用了这个解决方案,但不得不修改以下行:zfn = absfn[len(basedir)+len(os.sep):] 并将位置减去一,即: zfn = absfn[len(basedir)+len(os.sep)-1:] 否则文件名会缺少一个字母。 - Juan Osorio
@jfosoriot 1- 这是 Python 2.5 代码。请尝试使用 shutil.make_archive。2- 规范化 basedir 是否以路径分隔符(斜杠)结尾:if len(basedir) > 1: basedir = basedir.rstrip(os.sep) - jfs

5
这里是一个递归版本。
def zipfolder(path, relname, archive):
    paths = os.listdir(path)
    for p in paths:
        p1 = os.path.join(path, p) 
        p2 = os.path.join(relname, p)
        if os.path.isdir(p1): 
            zipfolder(p1, p2, archive)
        else:
            archive.write(p1, p2) 

def create_zip(path, relname, archname):
    archive = zipfile.ZipFile(archname, "w", zipfile.ZIP_DEFLATED)
    if os.path.isdir(path):
        zipfolder(path, relname, archive)
    else:
        archive.write(path, relname)
    archive.close()

0

jfs的解决方案和Kozyarchuk的解决方案都可以适用于OP的使用情况,但是:

  • jfs的解决方案将源文件夹中的所有文件压缩并存储在zip文件的根目录下(不保留原始源文件夹在zip结构中的位置)。
  • Kozyarchuk的解决方案由于是递归解决方案(例如,使用此代码创建新的zip文件“myzip.zip”将导致存档“myzip.zip”本身包含一个空文件“myzip.zip”),因此错误地将新创建的zip文件放入自身中。

因此,这里提供了一种解决方案,可以将源文件夹(以及任何深度的子文件夹)简单地添加到zip存档中。这是由于您无法将文件夹名称传递给内置方法ZipFile.write()而激发的 - 下面的函数add_folder_to_zip()提供了一种简单的方法来将文件夹及其所有内容添加到zip存档中。以下代码适用于Python2和Python3。

import zipfile
import os

def add_folder_to_zip(src_folder_name, dst_zip_archive):
    """ Adds a folder and its contents to a zip archive

        Args:
            src_folder_name (str): Source folder name to add to the archive
            dst_zip_archive (ZipFile):  Destination zip archive

        Returns:
            None
    """
    for walk_item in os.walk(src_folder_name):
        for file_item in walk_item[2]:
            # walk_item[2] is a list of files in the folder entry
            # walk_item[0] is the folder entry full path 
            fn_to_add = os.path.join(walk_item[0], file_item)
            dst_zip_archive.write(fn_to_add)

if __name__ == '__main__':
    zf = zipfile.ZipFile('myzip.zip', mode='w')
    add_folder_to_zip('zip_this_folder', zf)
    zf.close()

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