我有一段代码,我用它来搜索游戏文件的可执行文件并返回目录。我真的希望得到一些关于os.walk
的距离的进度指标。我将如何完成这样的事情?
我尝试了startpt = root.count(os.sep)
并测量了它,但这只是给出目录树中os.walk
的深度。
def locate(filelist, root=os.curdir): #Find a list of files, return directories.
for path, dirs, files in os.walk(os.path.abspath(root)):
for filename in returnMatches(filelist, [k.lower() for k in files]):
yield path + "\\"
答案 0 :(得分:5)
取决于!
如果文件和目录的分布或多或少均匀分布,则可以通过假设每个顶层目录占用相同的时间来显示粗略的过程。但是如果它们没有均匀分布,你就不能便宜地找到它。你要么必须事先知道每个目录的填充程度,要么你必须os.walk整个东西两次(但这只有在你的实际处理时间比os.walk本身要长得多时才有用。)
即:说你有4个顶级目录,每个目录包含4个文件。如果假设每个顶层目录占用了25%的进度,并且每个文件占用该目录的另外25%的进度,则可以显示一个很好的进度指示器。但是,如果最后一个子文件包含的文件比前几个更多,那么在您发现它之前,您的进度指示器将达到75%。如果os.walk本身就是瓶颈(而不是你的处理),你就无法解决这个问题,而且它是一个任意的目录树(不是你事先知道每个子树要花多长时间的那个)。
当然,假设每个文件的成本大致相同......
答案 1 :(得分:4)
只显示一个不确定的进度条(即显示blob来回弹跳或理发杆效果的进度条)。这样用户就知道该程序正在做一些有用的事情,但不会在完成时间等方面误导它们。
答案 2 :(得分:4)
我想出来了。
我使用os.listdir获取顶级目录列表,然后在os.walk返回的路径上使用.split函数,返回它当前所在的第一级目录。
这给我留下了一个顶级目录列表,我可以找到os.walk当前目录的索引,并将返回的索引与列表的长度进行比较,给出一个完整的%。 ;)
这并没有给我一个流畅的进度,因为每个目录中完成的工作量可能会有所不同,但平滑进度指示器对我来说无关紧要。但是可以通过将路径检查更深入地扩展到目录结构中来实现。
以下是获取进度的最终代码:
def locateGameDirs(filelist, root=os.curdir): #Find a list of files, return directories.
toplevel = [folder for folder in os.listdir(root) if os.path.isdir(os.path.join(root, folder))] #List of top-level directories
fileset = set(filelist)
for path, dirs, files in os.walk(os.path.abspath(root)):
curdir = path.split('\\')[1] #The directory os.walk is currently in.
try: #Thrown here because there's a nonexistant(?) first entry.
youarehere = toplevel.index(curdir)
progress = int(((youarehere)/len(toplevel))*100)
except:
pass
for filename in returnMatches(filelist, [k.lower() for k in files]):
yield filename, path + "\\", progress
现在出于调试目的,我在代码中进一步做了这个:
for wow in locateGameDirs(["wow.exe", "firefox.exe", "vlc.exe"], "C:\\"):
print wow
有没有一个很好的小方法来摆脱那个尝试/除外?似乎路径的第一次迭代没有给我什么......
答案 3 :(得分:2)
两次通过:首先计算树中总文件/文件夹的数量,然后在第二次通过期间进行实际处理。
答案 4 :(得分:0)
您需要知道要执行有意义的进度指示的文件总数 您可以获得这样的文件数
len(list(os.walk(os.path.abspath(root))))
但这需要一些时间,你可能需要一个进度指示器......
要快速查找文件数,您需要一个能够跟踪文件数量的文件系统。
也许您可以保存上次运行的总数并将其用作估算值
答案 5 :(得分:0)
我建议你避免走这个目录。而是使用基于索引的应用程序来快速查找文件。您可以通过子进程使用应用程序的命令行界面,几乎可以立即找到文件。
在Windows上,请参阅Everything。在UNIX上,查看locate。不确定Mac,但我确信那里也有一个选项。
答案 6 :(得分:0)
正如我在评论中所说,性能瓶颈可能位于locate
函数之外。你的returnMatches
是一个相当昂贵的功能。我认为你最好用以下代码替换它:
def locate(filelist, root=os.curdir)
fileset = set(filelist) # if possible, pass the set instead of the list as a first argument
for path, dirs, files in os.walk(os.path.abspath(root)):
if any(file.lower() in fileset for file in files):
yield path + '\\'
通过这种方式,您可以减少浪费操作的数量,在目录中每个文件生成一次(我认为这是您实际要做的事情)并且您可以同时忘记进度。我认为无论如何,进展都不是界面的预期特征。
答案 7 :(得分:0)
在这里开箱即用......如果你基于 尺寸 做了什么:
思想?
-AJ
答案 8 :(得分:0)
您可以进行一项优化 - 即使它永远不会更改,您也会在每次调用returnMatches时将文件列表转换为一个集合。将转换移动到'locate'函数的开头,并在每次迭代时传递set。
答案 9 :(得分:0)
嗯,这很有趣。这是另一种愚蠢的做法,但与其他一切一样,它只计算统一路径的正确进度。
import os, sys, time
def calc_progress(progress, root, dirs):
prog_start, prog_end, prog_slice = 0.0, 1.0, 1.0
current_progress = 0.0
parent_path, current_name = os.path.split(root)
data = progress.get(parent_path)
if data:
prog_start, prog_end, subdirs = data
i = subdirs.index(current_name)
prog_slice = (prog_end - prog_start) / len(subdirs)
current_progress = prog_slice * i + prog_start
if i == (len(subdirs) - 1):
del progress[parent_path]
if dirs:
progress[root] = (current_progress, current_progress+prog_slice, dirs)
return current_progress
def walk(start_root):
progress = {}
print 'Starting with {start_root}'.format(**locals())
for root, dirs, files in os.walk(start_root):
print '{0}: {1:%}'.format(root[len(start_root)+1:], calc_progress(progress, root, dirs))