13

我有一段代码用于搜索游戏文件的可执行文件并返回目录。我真的很想获得一些关于进展情况的进度指标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 + "\\"
4

10 回答 10

5

这取决于!

如果文件和目录或多或少地分布均匀,您可以通过假设每个顶级目录将花费相同的时间来显示粗略的过程。但是,如果它们分布不均,您就无法廉价地找到它。您要么必须事先大致了解每个目录的填充情况,要么必须 os.walk 整个过程两次(但这仅在您的实际处理时间比 os.walk 本身长得多的情况下才有用)。

即:假设您有 4 个顶级目录,每个目录包含 4 个文件。如果您假设每个顶级目录占用 25% 的进度,并且每个文件占用该目录的另外 25% 的进度,那么您可以显示一个不错的进度指示器。但是,如果最后一个子目录包含的文件比前几个子目录多得多,那么在您发现它之前,您的进度指示器将达到 75%。如果 os.walk 本身是瓶颈(不是您的处理)并且它是一个任意目录树(不是您事先知道每个子树大概需要多长时间的目录树),您就无法真正解决这个问题。

当然,这是假设每个文件的成本大致相同......

于 2010-01-29T19:29:35.830 回答
4

只需显示一个不确定的进度条(即显示来回弹跳的斑点或理发杆效果的进度条)。这样用户就知道该程序正在做一些有用的事情,但不会在完成时间等方面误导他们。

于 2010-01-29T19:45:51.300 回答
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

有没有一个很好的小方法来摆脱这种尝试/除外?似乎路径的第一次迭代没有给我任何东西......

于 2010-01-29T20:49:52.873 回答
2

分两遍进行:首先计算树中有多少文件/文件夹,然后在第二遍进行实际处理。

于 2010-01-29T19:04:24.467 回答
0

您需要知道文件总数才能做一个有意义的进度指示器。
你可以得到这样的文件数

len(list(os.walk(os.path.abspath(root))))

但这需要一些时间,您可能需要一个进度指示器...

要真正快速地找到文件数量,您需要一个文件系统来跟踪您的文件数量。

也许您可以保存上一次运行的总数并将其用作估计值

于 2010-01-29T19:19:28.390 回答
0

我建议你避免走目录。而是使用基于索引的应用程序来快速查找文件。您可以通过子进程使用应用程序的命令行界面,几乎可以立即找到文件。

在 Windows 上,请参阅Everything。在 UNIX 上,检查 locate。不确定Mac,但我相信那里也有一个选项。

于 2010-01-29T20:22:21.127 回答
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 + '\\'

这样可以减少浪费操作的数量,目录中的每个文件产生一次(我认为这是您实际缩进要做的事情)并且您可以同时忘记进度。无论如何,我认为进步不会是界面的预期功能。

于 2010-01-29T20:30:52.770 回答
0

在这里开箱即用……如果您根据尺寸来做会怎样:

  • 使用进程运行“du -sb”并获取根目录的总大小
  • 当你走路时,检查每个文件的大小并从你的 total_size 中减少(给你剩余的大小)
  • pct_complete = (total_size - remaining_size)/total_size

想法?

-aj

于 2010-01-29T20:31:46.003 回答
0

您可以做的一项优化 - 您在每次调用 returnMatches 时将文件列表转换为一个集合,即使它永远不会改变。将转换移动到“定位”函数的开头,并在每次迭代时传递集合。

于 2010-01-29T20:54:43.220 回答
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))
于 2010-01-29T21:36:09.120 回答