从列表中跳过文件时使用zipfile归档目录内容

时间:2018-12-22 02:17:10

标签: python python-3.x for-loop if-statement zipfile

我正在使用zipfile创建目录中所有文件的存档(递归,同时保留包括空文件夹的目录结构),并希望该过程跳过列表中指定的文件名。

这是os。遍历目录并将所有包含的文件和目录添加到存档中的基本功能。

def zip_dir(path):
    zipname = str(path.rsplit('/')[-1]) + '.zip'
    with zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED) as zf:
        if os.path.isdir(path):
            for root, dirs, files in os.walk(path):
                for file_or_dir in files + dirs:
                    zf.write(os.path.join(root, file_or_dir),
                            os.path.relpath(os.path.join(root, file_or_dir),
                            os.path.join(path, os.path.pardir)))
        elif os.path.isfile(filepath):
            zf.write(os.path.basename(filepath))
    zf.printdir()
    zf.close()

我们可以看到代码也应该具有处理单个文件的能力,但是它主要是与我们感兴趣的目录有关的部分。

现在,我们有一个文件名列表,希望将其排除在zip存档之外。

skiplist = ['.DS_Store', 'tempfile.tmp']

实现此目标的最好,最干净的方法是什么?

我尝试使用zip,虽然有些成功,但由于某种原因导致它排除了空文件夹(应包括空文件夹)。我不确定为什么会这样。

skiplist = ['.DS_Store', 'tempfile.tmp']
for root, dirs, files in os.walk(path):
    for (file_or_dir, skipname) in zip(files + dirs, skiplist):
        if skipname not in file_or_dir:
            zf.write(os.path.join(root, file_or_dir),
                    os.path.relpath(os.path.join(root, file_or_dir),
                    os.path.join(path, os.path.pardir)))

看看是否有人对增加跳过特定文件扩展名的能力有一个聪明的主意也很有趣,也许像.endswith('.png')之类的东西,但是我不完全确定如何将其与现有文件合并在一起跳过列表。

对于该功能的其他一般性评论,以及该功能是否确实可以按预期工作而又不出意外,以及对优化或改进的任何建议,我也将不胜感激。

1 个答案:

答案 0 :(得分:1)

您可以简单地检查文件是否不在skiplist

skiplist = {'.DS_Store', 'tempfile.tmp'}

for root, dirs, files in os.walk(path):
    for file in files + dirs:
        if file not in skiplist:
            zf.write(os.path.join(root, file),
                     os.path.relpath(os.path.join(root, file),
                     os.path.join(path, os.path.pardir)))

这将确保不会将skiplist中的文件添加到存档中。

另一种优化方法是将skiplist设置为一个集合,以防万一它变得很大,并且您希望使用列表来进行恒定时间O(1)查找,而不是线性O(N)查找。

您可以在TimeComplexity进行更多研究,它显示了数据结构上各种Python操作的时间复杂性。

对于扩展,您可以使用os.path.splitext()提取扩展并使用与上述相同的逻辑:

from os.path import splitext

extensions = {'.png', '.txt'}

for root, dirs, files in os.walk(path):
    for file in files:
        _, extension = splitext(file)
        if extension not in extensions:
            zf.write(os.path.join(root, file),
                     os.path.relpath(os.path.join(root, file),
                     os.path.join(path, os.path.pardir)))

如果要结合上述功能,则可以分别处理文件和目录的逻辑:

from os.path import splitext

extensions = {'.png', '.txt'}
skiplist = {'.DS_Store', 'tempfile.tmp'}

for root, dirs, files in os.walk(path):
    for file in files:
        _, extension = splitext(file)
        if file not in skiplist and extension not in extensions:
            zf.write(os.path.join(root, file),
                     os.path.relpath(os.path.join(root, file),
                     os.path.join(path, os.path.pardir)))

    for directory in dirs:
        if directory not in skiplist:
            zf.write(os.path.join(root, directory),
                     os.path.relpath(os.path.join(root, directory),
                     os.path.join(path, os.path.pardir))) 

注意:上面的代码段本身无法运行,您需要将当前代码进行编织才能使用这些想法。