Python 压缩一个子文件夹而不是整个文件夹路径

Posted

技术标签:

【中文标题】Python 压缩一个子文件夹而不是整个文件夹路径【英文标题】:Python zip a sub folder and not the entire folder path 【发布时间】:2013-01-21 12:45:11 【问题描述】:

我有一个程序可以压缩文件夹中的所有内容。我没有编写这段代码,但我在网上的某个地方找到了它,我正在使用它。我打算压缩一个文件夹,例如 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,我需要另一个解决方案:-/

【问题讨论】:

【参考方案1】:

您必须为使用相对路径的ZipFile.write() 提供arcname 参数。通过将要删除的根路径提供给 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() 函数仅适用于filepath 保证以root 开头的特定情况;在 Windows 上,relpath() 的一般情况要复杂得多。如果可能的话,您真的很想升级到 Python 2.6 或更高版本。

【讨论】:

我试过这个方法,但由于我使用的是 2.5,我认为我不能使用 relpath。我收到这条消息:文件“C:\Python25\example\fullzipnew.py”,第 14 行,在 makeArchive a.write(f, os.path.relpath(f, root)) AttributeError: 'module' object has no attribute '相对路径' @kraxter:确实,os.path.relpath() 是在 2.6 中添加的。为什么不升级你的python版本? 2.5 现在已经很老了。 我知道 :-/ 但现在我正在开发 2.5,您认为还有其他解决方法吗? :'( @kraxter:我已经更新了我的答案,以便为您的具体情况提供解决方法。 感谢您的工作。它按照我想要的方式工作。我知道我需要从 2.5 升级。很快! :)【参考方案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 的方法要优雅得多。

【讨论】:

如果path_prefix 不以斜杠结尾,您现在可以在arcname 的开头使用路径分隔符...... 我知道 - 因此我推荐了你的方法。 我试过这个方法,效果也一样。谢谢!

以上是关于Python 压缩一个子文件夹而不是整个文件夹路径的主要内容,如果未能解决你的问题,请参考以下文章

用python os walk解压30000个子文件夹中的bz2文件?

delphi项目程序输出编译成应用程序文件

如何在 Xcode 中获取 PNG 名称而不是整个目录路径?

检查路径在 Python 中是不是有效,而不在路径的目标处创建文件

求教,如何用批处理将每个子文件夹下所有内容压缩为zip

linux文件压缩