如何在python中获得os.walk的进度?

时间:2010-01-29 18:58:27

标签: python os.walk

我有一段代码,我用它来搜索游戏文件的可执行文件并返回目录。我真的希望得到一些关于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 + "\\"

10 个答案:

答案 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)

在这里开箱即用......如果你基于 尺寸 做了什么:

  • 使用子流程运行'du -sb'并获取根目录的total_size
  • 当你走路时,检查每个文件的大小并从你的total_size减去(给你remaining_size)
  • pct_complete =(total_size - remaining_size)/ total_size

思想?

-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))