递归深度有限的旅行目录树
Travel directory tree with limited recursion depth
我需要递归处理目录树中的所有文件,但深度有限。
这意味着例如在当前目录和前两个子目录级别中查找文件,但不能再进一步查找。在那种情况下,我必须处理例如./subdir1/subdir2/file
,但不是 ./subdir1/subdir2/subdir3/file
。
我如何在 Python 3 中做到最好?
目前我使用 os.walk
像这样循环处理所有文件直到无限深度:
for root, dirnames, filenames in os.walk(args.directory):
for filename in filenames:
path = os.path.join(root, filename)
# do something with that file...
我可以想出一种方法来计算 root
中的目录分隔符 (/
) 以确定当前文件的层次级别,如果该级别超过所需的最大值,则 break
循环.
我认为这种方法可能不安全,而且当有大量子目录要忽略时可能效率很低。这里的最佳方法是什么?
我认为最简单和最稳定的方法是复制 os.walk
straight out of the source 的功能并插入您自己的深度控制参数。
import os
import os.path as path
def walk(top, topdown=True, onerror=None, followlinks=False, maxdepth=None):
islink, join, isdir = path.islink, path.join, path.isdir
try:
names = os.listdir(top)
except OSError, err:
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
for name in names:
if isdir(join(top, name)):
dirs.append(name)
else:
nondirs.append(name)
if topdown:
yield top, dirs, nondirs
if maxdepth is None or maxdepth > 1:
for name in dirs:
new_path = join(top, name)
if followlinks or not islink(new_path):
for x in walk(new_path, topdown, onerror, followlinks, None if maxdepth is None else maxdepth-1):
yield x
if not topdown:
yield top, dirs, nondirs
for root, dirnames, filenames in walk(args.directory, maxdepth=2):
#...
如果您对所有这些可选参数不感兴趣,可以大幅缩减函数:
import os
def walk(top, maxdepth):
dirs, nondirs = [], []
for name in os.listdir(top):
(dirs if os.path.isdir(os.path.join(top, name)) else nondirs).append(name)
yield top, dirs, nondirs
if maxdepth > 1:
for name in dirs:
for x in walk(os.path.join(top, name), maxdepth-1):
yield x
for x in walk(".", 2):
print(x)
从 python 3.5 开始,os.scandir 用于 os.walk 而不是 os.listdir。它的工作速度快了很多倍。我稍微更正了@kevin 样本。
import os
def walk(top, maxdepth):
dirs, nondirs = [], []
for entry in os.scandir(top):
(dirs if entry.is_dir() else nondirs).append(entry.path)
yield top, dirs, nondirs
if maxdepth > 1:
for path in dirs:
for x in walk(path, maxdepth-1):
yield x
for x in walk(".", 2):
print(x)
我需要递归处理目录树中的所有文件,但深度有限。
这意味着例如在当前目录和前两个子目录级别中查找文件,但不能再进一步查找。在那种情况下,我必须处理例如./subdir1/subdir2/file
,但不是 ./subdir1/subdir2/subdir3/file
。
我如何在 Python 3 中做到最好?
目前我使用 os.walk
像这样循环处理所有文件直到无限深度:
for root, dirnames, filenames in os.walk(args.directory):
for filename in filenames:
path = os.path.join(root, filename)
# do something with that file...
我可以想出一种方法来计算 root
中的目录分隔符 (/
) 以确定当前文件的层次级别,如果该级别超过所需的最大值,则 break
循环.
我认为这种方法可能不安全,而且当有大量子目录要忽略时可能效率很低。这里的最佳方法是什么?
我认为最简单和最稳定的方法是复制 os.walk
straight out of the source 的功能并插入您自己的深度控制参数。
import os
import os.path as path
def walk(top, topdown=True, onerror=None, followlinks=False, maxdepth=None):
islink, join, isdir = path.islink, path.join, path.isdir
try:
names = os.listdir(top)
except OSError, err:
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
for name in names:
if isdir(join(top, name)):
dirs.append(name)
else:
nondirs.append(name)
if topdown:
yield top, dirs, nondirs
if maxdepth is None or maxdepth > 1:
for name in dirs:
new_path = join(top, name)
if followlinks or not islink(new_path):
for x in walk(new_path, topdown, onerror, followlinks, None if maxdepth is None else maxdepth-1):
yield x
if not topdown:
yield top, dirs, nondirs
for root, dirnames, filenames in walk(args.directory, maxdepth=2):
#...
如果您对所有这些可选参数不感兴趣,可以大幅缩减函数:
import os
def walk(top, maxdepth):
dirs, nondirs = [], []
for name in os.listdir(top):
(dirs if os.path.isdir(os.path.join(top, name)) else nondirs).append(name)
yield top, dirs, nondirs
if maxdepth > 1:
for name in dirs:
for x in walk(os.path.join(top, name), maxdepth-1):
yield x
for x in walk(".", 2):
print(x)
从 python 3.5 开始,os.scandir 用于 os.walk 而不是 os.listdir。它的工作速度快了很多倍。我稍微更正了@kevin 样本。
import os
def walk(top, maxdepth):
dirs, nondirs = [], []
for entry in os.scandir(top):
(dirs if entry.is_dir() else nondirs).append(entry.path)
yield top, dirs, nondirs
if maxdepth > 1:
for path in dirs:
for x in walk(path, maxdepth-1):
yield x
for x in walk(".", 2):
print(x)