【问题标题】:How to get all grandchildren of a directory in python with only one OS call如何仅通过一个操作系统调用在python中获取目录的所有孙子
【发布时间】:2013-03-06 19:54:21
【问题描述】:

我正在尝试在 Python 中获取某个目录的所有孙子。出于性能原因,我不想一直循环调用操作系统函数(它是一个网络文件系统)。这就是我目前所拥有的。有没有更简单的方法来做到这一点?

dirTree = os.walk(root)
children = [os.path.join(root, x) for x in dirTree.next()[1]]
grandChildren = []
for root, dirs, files in dirTree:
    if root in children:
        for dir in dirs:
            grandChildren.append(os.path.join(root, dir))

编辑:我不清楚我对 os.walk 的调用是否是懒惰的。我的意图是在我调用后整棵树都应该在内存中,但我不确定。

【问题讨论】:

  • 你看过unipath模块吗?
  • This answer 可能会有所启发。
  • 您是只对孙子感兴趣,还是对所有第二代和伟大的后代感兴趣?也就是说,“root/a/b/c/d”会被包含在您的搜索中还是从您的搜索中排除?

标签: python


【解决方案1】:

如果我没听错的话。

您可以使用 glob 通过提供通配符符号来获取文件或目录。例如,在列表中获取“/home/”中的所有目录。

glob.glob('/home/*/*/')

或者你也可以知道所有文件

glob.glob('/home/*/*')

【讨论】:

  • 这不是很有用,因为您必须知道每个目录中的子目录数量。
  • jjujuma: grandChildren = [dirpath.rstrip(os.sep) for dirpath in glob.iglob('/home/*/*/')] 生成与您的代码相同的列表。 rstrip() 删除列表中目录路径上的尾随路径分隔符。 @msvalkon:我相信你错了。
  • @martineau 啊是的,我理解grandChildren/foo/bar 的所有子目录。
【解决方案2】:

在 POSIX 或 Windows 中,您无法在一次操作系统调用中获取所有数据。对于 POSIX,每个目录至少有三个(opendirreaddirclose),每个目录条目加上一个(stat)。


我相信接下来的内容将导致操作系统调用少于您发布的内容。是的,os.walk() 调用是懒惰的;也就是说,整个树在从walk() 返回时在内存中,而是在调用next() 期间被零碎地读取。

因此,我的版本将仅读取一阶后代目录,并且将 stat 仅读取直系子孙。您的版本也适用于所有曾孙,只要您的目录结构有多深。

root='.'
grandChildren = []
for kid in next(os.walk('.'))[1]:
  x = next(os.walk(os.path.join('.', kid)))
  for grandKid in x[1]:  # (or x[1]+x[2] if you care about regular files)
    grandChildren.append(os.path.join(x[0], grandKid))

或者,作为列表推导而不是 for 循环:

import os
root='.'
grandChildren = [
  os.path.join(kid, grandKid)
  for kid in next(os.walk(root))[1]
    for grandKid in next(os.walk(os.path.join(root, kid)))[1]]

最后,将os.walks 分解成一个函数:

def read_subdirs(dir='.'):
  import os
  return (os.path.join(dir,x) for x in next(os.walk(dir))[1])

root='.'
grandChildren = [
  grandKid
  for kid in read_subdirs(root)
    for grandKid in read_subdirs(kid)]


从测试中我们可以看到,如果有曾孙,我的版本调用stat 的次数比你的少很多。

例如,在我的主目录中,我运行了我的代码 (/tmp/a.py) 和你的代码 (/tmp/b.py),其中 root 在每种情况下都设置为 '.'

$ strace -e stat python /tmp/a.py 2>&1 > /dev/null | egrep -c stat
1245
$ strace -e stat python /tmp/b.py 2>&1 > /dev/null | egrep -c stat
36049

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-16
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 2017-04-10
    • 1970-01-01
    相关资源
    最近更新 更多