我想以递归方式遍历一个目录,但如果遇到一个包含100个以上文件的目录,我希望python从任何一个listdir中断。基本上,我正在搜索(.TXT)文件,但我想避免使用大型DPX图像序列(通常是10,000个文件)的目录。由于DPX独立地存在于目录中而没有子目录,所以我想尽快打破这个循环。
长话短说,如果python遇到匹配“.DPX $”的文件,它会停止列出子目录,退出,跳过该子目录并继续遍历其他子目录。
是否可以在返回所有列表结果之前中断目录列表循环?
答案 0 :(得分:4)
如果通过'目录列表循环'你的意思是os.listdir()
然后没有。这是不能打破的。但是,您可以查看os.path.walk()
或os.walk()
方法,只删除包含DPX
个文件的所有目录。如果您使用os.walk()
并且正在自上而下行走,您可以通过修改目录列表来影响Python进入的目标。 os.path.walk()
允许您使用访问方法选择行走方式。
答案 1 :(得分:2)
根据os.walk
的{{3}}:
当自上而下为
True
时,来电者可以就地修改 dirnames 列表 (例如,通过del
或切片分配),而walk()
只会递归到。{ 名称保留在 dirnames 中的子目录;这可以用来修剪 搜索,或强制执行特定的访问顺序。修改 当 topdownFalse
无效时 dirnames ,因为目录中的 dirnames 已经在 dirnames 本身时生成了 生成。
理论上,如果你清空dirnames
,那么os.walk
将不会递减任何其他目录。注意关于“......通过del或slice赋值”的评论;您不能简单地执行dirnames=[]
,因为这实际上不会影响dirnames
列表的内容。
答案 2 :(得分:1)
避免使用os.listdir分配名称列表的正确方法是使用os级别函数,如@Charles Duffy所说。
受到其他帖子的启发:List files in a folder as a stream to begin process immediately
我添加了如何解决特定的OP问题并使用了函数的可重入版本。
from ctypes import CDLL, c_char_p, c_int, c_long, c_ushort, c_byte, c_char, Structure, POINTER, byref, cast, sizeof, get_errno
from ctypes.util import find_library
class c_dir(Structure):
"""Opaque type for directory entries, corresponds to struct DIR"""
pass
class c_dirent(Structure):
"""Directory entry"""
# FIXME not sure these are the exactly correct types!
_fields_ = (
('d_ino', c_long), # inode number
('d_off', c_long), # offset to the next dirent
('d_reclen', c_ushort), # length of this record
('d_type', c_byte), # type of file; not supported by all file system types
('d_name', c_char * 4096) # filename
)
c_dirent_p = POINTER(c_dirent)
c_dirent_pp = POINTER(c_dirent_p)
c_dir_p = POINTER(c_dir)
c_lib = CDLL(find_library("c"))
opendir = c_lib.opendir
opendir.argtypes = [c_char_p]
opendir.restype = c_dir_p
readdir_r = c_lib.readdir_r
readdir_r.argtypes = [c_dir_p, c_dirent_p, c_dirent_pp]
readdir_r.restype = c_int
closedir = c_lib.closedir
closedir.argtypes = [c_dir_p]
closedir.restype = c_int
import errno
def listdirx(path):
"""
A generator to return the names of files in the directory passed in
"""
dir_p = opendir(path)
if not dir_p:
raise IOError()
entry_p = cast(c_lib.malloc(sizeof(c_dirent)), c_dirent_p)
try:
while True:
res = readdir_r(dir_p, entry_p, byref(entry_p))
if res:
raise IOError()
if not entry_p:
break
name = entry_p.contents.d_name
if name not in (".", ".."):
yield name
finally:
if dir_p:
closedir(dir_p)
if entry_p:
c_lib.free(entry_p)
if __name__ == '__main__':
import sys
path = sys.argv[1]
max_per_dir = int(sys.argv[2])
for idx, entry in enumerate(listdirx(path)):
if idx >= max_per_dir:
break
print entry