如何获取Python中os.walk的进度?

14 投票
10 回答
10009 浏览
提问于 2025-04-15 18:39

我有一段代码,用来搜索游戏文件的可执行文件,并返回它们所在的目录。我想要一个进度指示器,显示一下 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 个回答

4

只需要显示一个不确定的进度条(比如那种显示一个小球来回弹跳的,或者像理发店的那种条纹效果)。这样用户就知道程序在做一些有用的事情,但不会让他们误以为完成需要多长时间。

5

这要看情况!

如果文件和文件夹分布得差不多均匀,你可以假设每个顶级文件夹花费的时间差不多,这样就能大致显示进度。但是如果它们分布得不均匀,那就不容易找到这个信息。你要么事先大致知道每个文件夹里有多少文件,要么就得用os.walk遍历整个目录两次(不过这只有在你的实际处理时间远远超过os.walk的时间时才有意义)。

举个例子,假设你有4个顶级文件夹,每个文件夹里有4个文件。如果你假设每个顶级文件夹占25%的进度,每个文件又占该文件夹25%的进度,那你就可以显示一个不错的进度指示器。但如果最后一个子文件夹里的文件比前几个多得多,你的进度指示器可能在你发现之前就已经显示到75%了。如果os.walk本身就是瓶颈(而不是你的处理),而且目录结构又是随机的(你事先不知道每个子树大概需要多长时间),那就很难解决这个问题。

当然,这还得假设每个文件的处理成本差不多一样……

6

我搞明白这个问题了。

我使用了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

有没有什么简单的方法来去掉那个try/except?因为路径的第一次迭代给我的结果是空的...

撰写回答