python os.walk如何还原所有路径名_关于python:使用os.walk定位目录

由于目录结构庞大且令人费解,我的脚本正在搜索太多目录:

root--

|

--Project A--

|

-- Irrelevant

-- Irrelevant

-- TARGET

|

--Project B--

|

-- Irrelevant

-- TARGET

-- Irrelevant

|

-- Irrelevant  --

|

--- Irrelevant

TARGET目录是我唯一需要遍历的目录,并且在每个项目中都有一个一致的名称(在这里我们将其命名为Target)。

我看着这个问题:

排除os.walk中的目录

但是除了排除之外,我需要包括" target"目录,该目录不是" root"级别,而是下一级。

我已经尝试过类似的东西:

def walker(path):

for dirpath, dirnames, filenames in os.walk(path):

dirnames[:] = set(['TARGET'])

但这会影响根目录(从而忽略了它需要遍历的所有目录,Project A,Project B ...)

试试:if TARGET in dirnames: dirnames[:] = [TARGET] ...

使用glob.glob首先获取"目标"子目录的列表,然后在结果上使用os.listdir或os.walk呢?

@CAB这意味着walk不会超过根目录。

@CAB您可能是说else dirnames。 否则,您将结束递归,并且由于根目录不包含TARGET,您最终将无济于事。

您可以只消耗第一个值。 o=os.walk(path) _=next(o)然后输入您的代码

代码的问题在于,您总是在修改dirnames列表,但这意味着即使在根级别,所有子目录也都被删除,因此递归调用最终不会访问各个Project X目录。

您想要的是仅在TARGET存在时清除其他目录:

if 'TARGET' in dirnames:

dirnames[:] = ['TARGET']

这将允许os.walk调用访问Project X目录,但是将阻止它进入Irrelevant目录。

如果初始路径为root,似乎这样将不会执行任何操作,因为它不包含名为TARGET的子目录。

@martineau是的,这是正确的。通过不删除目录名,它确实可以递归到其他目录,这就是答案所在。

啊,对...现在我明白了。好答案。

对于这样的白名单场景,建议使用glob.iglob通过模式获取目录。它是一个生成器,因此您将尽快获得每个结果(注意:在编写本文时,它仍然是使用os.listdir而不是os.scandir来实现的,因此它只是生成器的一半;每个目录会急切地进行扫描,但只有在完成从当前目录产生值后才扫描下一个目录)。例如,在这种情况下:

from future_builtins import filter  # Only on Py2 to get generator based filter

import os.path

import glob

from operator import methodcaller

try:

from os import scandir       # Built-in on 3.5 and above

except ImportError:

from scandir import scandir  # PyPI package on 3.4 and below

# If on 3.4+, use glob.escape for safety; before then, if path might contain glob

# special characters and you don't want them processed you need to escape manually

globpat = os.path.join(glob.escape(path), '*', 'TARGET')

# Find paths matching the pattern, filtering out non-directories as we go:

for targetdir in filter(os.path.isdir, glob.iglob(globpat)):

# targetdir is the qualified name of a single directory matching the pattern,

# so if you want to process the files in that directory, you can follow up with:

for fileentry in filter(methodcaller('is_file'), scandir(targetdir)):

# fileentry is a DirEntry with attributes for .name, .path, etc.

有关更多高级用法,请参阅os.scandir上的文档,或者您可以仅使内部循环调用os.walk来保留大部分原始代码。

如果您确实必须使用os.walk,则可以更轻松地修剪dirs。由于您指定的所有TARGET目录应仅向下一级,因此实际上非常简单。默认情况下,os.walk自上而下,这意味着第一组结果将是根目录(您不希望仅将其修剪到TARGET条目)。因此,您可以执行以下操作:

import fnmatch

for i, (dirpath, dirs, files) in enumerate(os.walk(path)):

if i == 0:

# Top level dir, prune non-Project dirs

dirs[:] = fnmatch.filter(dirs, 'Project *')

elif os.path.samefile(os.path.dirname(dirpath), path):

# Second level dir, prune non-TARGET dirs

dirs[:] = fnmatch.filter(dirs, 'TARGET')

else:

# Do whatever handling you'd normally do for files and directories

# located under path/Project */TARGET/

我是否弄错了,或者如果目录嵌套的层次可能超过一级,则失败吗?并且,如果这没有失败,则意味着它仍将列出Irrelevant目录的内容,并针对其中的每个路径检查其是否验证了模式,但仍然必须浪费时间。

@Bakuriu:如果它们可能嵌套了多个层次,请创建globpat = os.path.join(glob.escape(path), **, TARGET)并进行iglob调用glob.iglob(globpat, recursive=True),它将无限期下降。 OP似乎希望将其精确降低一级,因此不需要深度递归。您也可以调整通配符以避免该单层情况下的Irrelevant目录,例如将*组件替换为Project [AB]进行非常有针对性的选择,或者将Project *替换为任何带有Project前缀的目录。

是的,但是我的意思是,如果您使用**,您的答案将变得无效。 iglob无法知道Irrelevant以下的内容无关紧要,但仍然必须检查所有这些内容(如果Irrelevant包含数百万个文件或嵌套的子目录,则将花费大量时间)。

@Bakuriu:好的。但是然后,OP不需要**。当然,对于在大树中进行深度递归搜索的非常细粒度的过滤器而言,通配很简单,但速度很慢。但是对于OP来说,应该没问题。我确实添加了一个涉及更多的完全过滤os.walk解决方案以提高完整性,该解决方案专门过滤了顶层和第二层,因此它仅完全处理Project *TARGET下的树。但是,如果TARGET可以处于任何深度,这都不会节省您的工作,您仍然会在Project *下的所有内容中寻找TARGET目录。

@Bakuriu:虽然它与此处的单级检查无关,但我确实注意到您想避免glob的一个原因:它遵循符号链接,不能被告知不要这样做。您可能想要这样做,但是它相对较少,并且存在风险(循环引用,或者只是引用了您不想搜索的巨大目录)。 os.walk可以跟随符号链接,但默认情况下不包含。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值