Python:如何迭代除文件中定义的通配符排除之外的所有目录?

2024-06-17 10:17:53 发布

您现在位置:Python中文网/ 问答频道 /正文

所以基本上我想迭代我的文件系统,从“/”(Unix)开始,除了我想从文件中读取的排除项,也可以是列表、生成器或其他任何东西。 让我们举个例子:

# What I want to exclude in a file
# (Just few examples)
EXCLUSIONS = ['/sys/*', '/var/lock/*, '*.pyc/*']

我的想法是:

import fnmatch

for exclude in EXCLUSIONS:
    for root, dirs, files in os.walk('/'):
        path = root.split(os.sep)
        for p in path:
            for f in files:
                tmp = p + f
                if fnmatch.fnmatch(tmp, exclude):
                    ...

我想这是非常低效的,这就是为什么它不起作用。 也许有人能给我一个提示或者知道一个方法来做到这一点


Tags: pathin列表forosunixrootfiles
3条回答

假设我们的排除规则是“根据fnmatch.fnmatch的逻辑,路径匹配EXCLUSIONSany”,我们可以编写一个函数来封装:

def should_exclude(path):
    return any(fnmatch.fnmatch(path, exclude) for exclude in EXCLUSIONS)

(我们可以通过接受排除作为第一个参数,而不是依赖全局参数,然后使用functools.partial绑定它来概括这一点。)

使os.walk远离修剪过的目录的方法是自上而下(默认)修改生成的子目录列表。我们希望迭代地将规则应用于列表,同时修改它,这is tricky;我所能想到的最优雅的方法是使用列表理解创建修改后的版本,然后将其切回原位:

def filter_inplace(source, exclude_rule):
    source[:] = [x for x in source if not exclude_rule(x)]

(注意这里的泛化;我们希望将过滤谓词should_exclude作为参数传递。)

现在我们应该能够使用os.walk,如文档所示:

def filtered_walk(root):
    for subroot, dirs, files in os.walk(root):
        yield subroot, files # the current result
        filter_inplace(dirs, should_exclude) # set up filtered recursion

这可以根据您的具体要求以多种方式进行更改。例如,您可以在filesos.path.join上迭代到subrootyield上,分别处理每个结果。值得一试和调试,以确保您准确理解迭代的每个步骤中subrootdirsfiles的样子,并验证过滤是否给出了您期望的结果

因此,@Karl Knechtel的回答让我想到了以下几点:

import fnmatch
import os

EXCLUSIONS = [...]     # Defined Files / Paths to exclude.

# A function to check each path / file
# against the EXCLUSIONS
def should_exclude(path) -> bool:
    return any(fnmatch.fnmatch(path, exclude) for exclude in EXCLUSIONS)

# A function to filter out unwanted files.
def filter_path(source, rule) -> str:
    # Just return wanted paths.
    if not rule(source):
        return source

# Now the function to walk through the
# given path.
def filtered_walk(path):
    for root, dirs, files in os.walk(path):
        # Now create real paths from dirs
        for d in dirs:
            tmp_dir = os.path.realpath(os.path.join(root, d))
            if filter_path(tmp_dir, should_exclude):
                yield tmp_dir

        # To reach the files the same procedure.
        for f in files:
            ...
            # Same logic as above..

我仍然认为这仍然是没有效率的,尤其是对于更大的文件系统。可能是可以优化的

import os

exclude = ['gui', 'sys']


def bypass_dirs(path, exclude_dirs):
    if os.path.split(path)[-1] in exclude_dirs:
        return
    try:
        dirs = os.listdir(path)
        for dir_path in dirs:
            bypass_dirs(os.path.join(path, dir_path), exclude_dirs)
    except NotADirectoryError:
        return
    except PermissionError:
        print('Permission Error', path)
        return
    except FileNotFoundError:
        return


bypass_dirs('/', exclude)

此代码允许您通过所有文件系统。可以选择“输入点”和“排除目录”。它有非常简单的排除机制,但您可以根据自己的方便程度对其进行更改

相关问题 更多 >