Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用zipfile存档目录内容,同时从列表中跳过文件_Python_Python 3.x_For Loop_If Statement_Zipfile - Fatal编程技术网

Python 使用zipfile存档目录内容,同时从列表中跳过文件

Python 使用zipfile存档目录内容,同时从列表中跳过文件,python,python-3.x,for-loop,if-statement,zipfile,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.

我正在使用
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')
,但我不完全确定如何将它与现有的skiplist结合起来


如果您对该功能有任何其他的一般性意见,以及它是否确实如预期的那样毫无意外地工作,以及对优化或改进的任何建议,我将不胜感激。

您只需检查文件是否不在
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)查找

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

对于扩展,您可以使用来提取扩展,并使用与上面相同的逻辑:

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))) 

注意:上述代码片段本身无法工作,您需要在当前代码中进行编织才能使用这些想法

@noob不用担心,很高兴我能帮上忙。但是我不确定我是否完全理解你所说的“另一个优化是让skiplist成为一个列表,以防它变得非常大,并且你需要固定时间的O(1)查找,而不是使用列表进行的线性O(N)查找。”的意思。你能详细说明一下吗?@noob这是我的一种类型,我已经编辑了答案。你知道大O符号的时间复杂性吗?它基本上意味着,当您使用
集合时,您可以直接散列到所需的项,即O(1)。如果使用列表,底层代码必须遍历整个列表以检查它是否存在。我在答案中添加了一个链接,指向记录这些时间复杂性的地方。在研究这个问题之前,也许值得先研究大O符号。基本上,O(1)比O(N)更有效。谢谢你的回复。为了澄清,这是你在回答中使用的一组,对吗?如果我理解正确的话,基本上是用花括号{}代替[]来利用常数时间O(1)查找。我不知道为什么要使用lists[],但也许这是另一个问题。@noob是的,花括号是一个集合。您还可以使用
set()
来定义它。集合是无序的,所以如果您需要保持顺序,那么使用列表是更好的选择,因为列表是有序的。对于这个问题,由于您只需要进行查找以检查要跳过的文件/扩展名,因此使用集合是更好的选择。但对于其他场景,情况可能并非如此。这真的取决于你解决了什么问题。