【问题标题】:How to optimize search with list dir and path walk?如何使用 list dir 和 path walk 优化搜索?
【发布时间】:2015-11-18 16:04:44
【问题描述】:

Python 2.7.5 Win/Mac。

我正在尝试找到在多个存储(大约 128Tio)上搜索文件(超过 10000 个)的最佳方法。这些文件有特定的扩展名,我可以忽略一些文件夹。

这是我使用os.listdir 和递归的第一个函数:

count = 0
def SearchFiles1(path):
    global count
    pathList = os.listdir(path)
    for i in pathList:
        subPath = path+os.path.sep+i
        if os.path.isfile(subPath) == True :
            fileName = os.path.basename(subPath)
            extension = fileName[fileName.rfind("."):]
            if ".ext1" in extension or ".ext2" in extension or ".ext3" in extension:
                count += 1
                #do stuff . . .
        else :
            if os.path.isdir(subPath) == True:
                if not "UselessFolder1" in subPath and not "UselessFolder1" in subPath:
                    SearchFiles1(subPath)

它有效,但我认为它可能会更好(更快和正确)还是我错了?

所以我尝试了os.path.walk

def SearchFiles2(path):
    count = 0
    for dirpath, subdirs, files in os.walk(path):
        for i in dirpath:
            if not "UselessFolder1" in i and not "UselessFolder1" in i:
                for y in files:
                    fileName = os.path.basename(y)
                    extension = fileName[fileName.rfind("."):]
                    if ".ext2" in extension or ".ext2" in extension or ".ext3" in extension:
                        count += 1
                        # do stuff . . .
    return count

“count”是错误的,而且速度较慢。而且我想我不太明白path.walk 的工作原理。

我的问题是:我可以做些什么来优化这项研究?

【问题讨论】:

    标签: python search os.path listdir


    【解决方案1】:

    您的第一个解决方案是合理的,只是您可以使用os.path.splitext。在第二个解决方案中,它不正确,因为您重新访问每个子目录的文件列表,而不是只处理一次。使用os.path.walk 的诀窍是从subdirs 删除的目录不是下一轮枚举的一部分。

    def SearchFiles2(path):
        useless_dirs = set(("UselessFolder1", "UselessFolder2"))
        useless_files = set((".ext1", ".ext2"))
        count = 0
        for dirpath, subdirs, files in os.walk(path):
            # remove unwanted subdirs from future enumeration
            for name in set(subdirs) & useless_dir:
                subdirs.remove(name)
            # list of interesting files
            myfiles = [os.path.join(dirpath, name) for name in files
                if os.path.splitext(name)[1] not in useless_files]
            count += len(myfiles)
            for filepath in myfiles:
                # example shows file stats
                print(filepath, os.stat(filepath)
        return count
    

    枚举单个存储单元的文件系统只能这么快。加快速度的最佳方法是在不同线程中运行不同存储单元的枚举。

    【讨论】:

    • 感谢您的示例,我改进了第一个解决方案(os.path.splitext 并将字符串与元组内容进行比较)。它有点快,我们可以轻松添加更多规则(文件 ext / 忽略子目录)。
    • 对于第二个解决方案,我没能成功。首先我猜它是第 7 行中的“useless_dirs”,但我得到了错误:“ValueError: list.remove(x): x not in list”。我添加了“打印名称”,看到它尝试从子目录中删除 useless_dirs[x],即使它不存在。
    • @Syrius 我的错...我使用了and,而我应该使用&
    • 现在可以正常使用了!最后一件事。如何获取文件的完整路径?我将:myfiles = [name for name in files if os.path.splitext(name)[1] not in useless_files] count += len(myfiles) 替换为 for f in [name for name in files if os.path.splitext(name)[1] in target_files]: count += 1 # do stuff . . . 目标不仅是计数,还要进行复制、获取大小或日期等。但 f 只给出文件名。
    • @Syrius 我已更新示例以创建可用于其他操作的文件路径。
    【解决方案2】:

    因此,在与 tdelaney 进行测试和讨论后,我对这两种解决方案进行了如下优化:

    import os
    
    count = 0
    target_files = set((".ext1", ".ext2", ".ext3")) # etc
    useless_dirs = set(("UselessFolder2", "UselessFolder2")) # etc
    # it could be target_dirs, just change `in` with `not in` when compared.
    
    def SearchFiles1(path):
        global count
        pathList = os.listdir(path)
        for content in pathList:
            fullPath = os.path.join(path,content)
            if os.path.isfile(fullPath):
                if os.path.splitext(fullPath)[1] in target_files:
                    count += 1
                    #do stuff with 'fullPath' . . .
            else :
                if os.path.isdir(fullPath):
                    if fullPath not in useless_dirs:
                        SearchFiles1(fullPath)
    
    def SearchFiles2(path):
        count = 0
        for dirpath, subdirs, files in os.walk(path):
            for name in set(subdirs) & useless_dirs:
                subdirs.remove(name)
            for filename in [name for name in files if os.path.splitext(name)[1] in target_files]:
                count += 1
                fullPath = os.path.join(dirpath, filename)
                #do stuff with 'fullPath' . . .
        return count
    

    在 Mac/PC v2.7.5 上运行良好

    关于速度,完全一致。

    【讨论】:

      猜你喜欢
      • 2021-07-01
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 2019-10-17
      • 2016-12-05
      相关资源
      最近更新 更多