在使用 Python 的 os.walk 函数遍历文件系统时,如果文件和目录数量较多,用户可能会希望看到一个进度条来了解遍历的进展情况。但是,os.walk 函数本身并不提供进度条功能。
2. 解决方案
方法一:估算进度
如果文件和目录分布相对均匀,并且每个顶级目录需要花费的时间大致相同,那么可以根据顶级目录的数量来估算进度。例如,如果有 10 个顶级目录,每个顶级目录包含 100 个文件,则可以假设每个顶级目录需要花费 10% 的时间,每个文件需要花费 1% 的时间。这样就可以根据 os.walk 函数遍历到的当前目录的深度来计算出当前的进度。
import os
def locate(filelist, root=os.curdir):
# 获取顶级目录列表
toplevel_dirs = [d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d))]
# 计算顶级目录的数量
num_toplevel_dirs = len(toplevel_dirs)
# 计算每个顶级目录需要花费的时间(以百分比表示)
time_per_toplevel_dir = 100 / num_toplevel_dirs
# 计算每个文件需要花费的时间(以百分比表示)
time_per_file = 1
# 创建进度条
progress_bar = ProgressBar(max_value=num_toplevel_dirs)
# 遍历文件系统
for path, dirs, files in os.walk(os.path.abspath(root)):
# 获取当前顶级目录的索引
curdir = path.split('\')[1]
toplevel_dir_index = toplevel_dirs.index(curdir)
# 计算当前进度
progress = (toplevel_dir_index * time_per_toplevel_dir) + (len(files) * time_per_file)
# 更新进度条
progress_bar.update(progress)
# 查找匹配的文件
for filename in returnMatches(filelist, [k.lower() for k in files]):
yield path + "\" + filename
# 使用进度条
for filename, path, progress in locate(["wow.exe", "firefox.exe", "vlc.exe"], "C:\"):
print(f"{filename} found in {path} ({progress:.2f}%)")
方法二:两次遍历
另一种方法是将遍历过程分成两步:第一步是计算文件和目录的总数,第二步是进行实际的处理。这样就可以在第一遍遍历中计算出总进度,然后在第二遍遍历中根据当前处理的文件或目录的数量来计算出当前进度。
import os
def locate(filelist, root=os.curdir):
# 计算文件和目录的总数
num_files_and_dirs = 0
for path, dirs, files in os.walk(os.path.abspath(root)):
num_files_and_dirs += len(dirs) + len(files)
# 创建进度条
progress_bar = ProgressBar(max_value=num_files_and_dirs)
# 遍历文件系统并进行实际的处理
for path, dirs, files in os.walk(os.path.abspath(root)):
# 更新进度条
progress_bar.update(len(dirs) + len(files))
# 查找匹配的文件
for filename in returnMatches(filelist, [k.lower() for k in files]):
yield path + "\" + filename
# 使用进度条
for filename, path in locate(["wow.exe", "firefox.exe", "vlc.exe"], "C:\"):
print(f"{filename} found in {path}")
方法三:不显示进度条
如果对进度条没有要求,那么可以简单地使用 os.walk 函数遍历文件系统,并在遍历过程中进行相应的处理。
import os
def locate(filelist, root=os.curdir):
# 遍历文件系统
for path, dirs, files in os.walk(os.path.abspath(root)):
# 查找匹配的文件
for filename in returnMatches(filelist, [k.lower() for k in files]):
yield path + "\" + filename
# 使用不带进度条的遍历
for filename, path in locate(["wow.exe", "firefox.exe", "vlc.exe"], "C:\"):
print(f"{filename} found in {path}")