10

我有一个程序可以压缩文件夹中的所有内容。我没有编写这段代码,但我在网上的某个地方找到了它,我正在使用它。我打算压缩一个文件夹,例如 C:/folder1/folder2/folder3/ 。我想将文件夹 3 及其所有内容压缩到一个文件中,比如文件夹 3.zip。使用下面的代码,一旦我压缩它,folder3.zip 的内容将是 folder1/folder2/folder3/and files。我不希望整个路径被压缩,我只希望我对压缩感兴趣的子文件夹(在本例中为文件夹 3)。我尝试了一些 os.chdir 等,但没有运气。

def makeArchive(fileList, archive):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    try:
        a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

        for f in fileList:
            print "archiving file %s" % (f)
            a.write(f)
        a.close()
        return True
    except: return False 

def dirEntries(dir_name, subdir, *args):
    # Creates a list of all files in the folder
    '''Return a list of file names found in directory 'dir_name'
    If 'subdir' is True, recursively access subdirectories under 'dir_name'.
    Additional arguments, if any, are file extensions to match filenames. Matched
        file names are added to the list.
    If there are no additional arguments, all files found in the directory are
        added to the list.
    Example usage: fileList = dirEntries(r'H:\TEMP', False, 'txt', 'py')
        Only files with 'txt' and 'py' extensions will be added to the list.
    Example usage: fileList = dirEntries(r'H:\TEMP', True)
        All files and all the files in subdirectories under H:\TEMP will be added
        to the list. '''

    fileList = []
    for file in os.listdir(dir_name):
        dirfile = os.path.join(dir_name, file)
        if os.path.isfile(dirfile):
            if not args:
                fileList.append(dirfile)
            else:
                if os.path.splitext(dirfile)[1][1:] in args:
                    fileList.append(dirfile)
            # recursively access file names in subdirectories
        elif os.path.isdir(dirfile) and subdir:
            print "Accessing directory:", dirfile
            fileList.extend(dirEntries(dirfile, subdir, *args))
    return fileList

您可以通过 调用它makeArchive(dirEntries(folder, True), zipname)

关于如何解决这个问题的任何想法?我正在使用 Windows 操作系统和 python 25,我知道在 python 2.7 中有 shutil make_archive 有帮助,但由于我正在使用 2.5,我需要另一个解决方案:-/

4

2 回答 2

21

您必须给出一个使用相对路径的arcname参数。ZipFile.write()通过提供要删除的根路径来做到这一点makeArchive()

def makeArchive(fileList, archive, root):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

    for f in fileList:
        print "archiving file %s" % (f)
        a.write(f, os.path.relpath(f, root))
    a.close()

并调用它:

makeArchive(dirEntries(folder, True), zipname, folder)

我已经把毯子拿走了try:except:; 这里没有用,只会隐藏你想知道的问题。

os.path.relpath()函数返回相对于 的路径root,有效地从存档条目中删除该根路径。

在 python 2.5 上,该relpath功能不可用;对于这个特定的用例,以下替换将起作用:

def relpath(filename, root):
    return filename[len(root):].lstrip(os.path.sep).lstrip(os.path.altsep)

并使用:

a.write(f, relpath(f, root))

请注意,上述功能仅适用于您保证以;开头relpath()的特定情况。在 Windows 上,一般情况要复杂得多。如果可能的话,您真的很想升级到 Python 2.6 或更高版本。filepathrootrelpath()

于 2013-01-21T13:04:54.063 回答
2

ZipFile.write有一个可选参数arcname。使用它来删除部分路径。

您可以将方法更改为:

def makeArchive(fileList, archive, path_prefix=None):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    try:
        a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

        for f in fileList:
            print "archiving file %s" % (f)
            if path_prefix is None:
                a.write(f)
            else:
                a.write(f, f[len(path_prefix):] if f.startswith(path_prefix) else f)
        a.close()
        return True
    except: return False 

不过,Martijn 使用 os.path 的方法要优雅得多。

于 2013-01-21T13:02:56.943 回答