【问题标题】:Search a very large directory for a file containing text in it's name在一个非常大的目录中搜索名称中包含文本的文件
【发布时间】:2023-02-07 09:43:39
【问题描述】:

我有一个网络共享,其中包含大约 300,000 个文件,并且它不断变化(添加和删除文件)。我想在目录中搜索特定文本以在此目录中查找某些文件。我已经尽可能地减少了我的方法,但它仍然需要 6 分钟多才能完成。我大概可以同时手动执行此操作,具体取决于我要搜索的字符串数量。我想对其进行多线程或多处理,但我不确定如何在一次调用中完成:即

for filename in os.scandir(sourcedir)

谁能帮我解决这个问题?

def scan(sourcedir:str, oset:set[str]|str) -> set[str]:
    found = set()
        for filename in os.scandir(sourcedir):
            for ordr in oset:
                if ordr in filename.name:
                    print(filename.name)
                    found.add(filename.name)
                    break

典型呼叫的结果: 在 395.033 秒内调用了 516 个函数

排序依据:标准名称

ncalls tottime percall cumtime percall 文件名:lineno(函数) 6 0.000 0.000 0.003 0.000:39(伊斯迪尔) 6 0.000 0.000 1.346 0.224 :94(同一个文件) 12 0.000 0.000 0.001 0.000 :103(加入) 30 0.000 0.000 0.000 0.000 :150(分离驱动) 6 0.000 0.000 0.000 0.000 :206(拆分) 6 0.000 0.000 0.000 0.000 :240(基名) 6 0.000 0.000 0.000 0.000 :35(_get_bothseps) 1 0.000 0.000 0.000 0.000 :545(规范路径) 1 0.000 0.000 0.000 0.000 :577(绝对路径) 1 0.000 0.000 395.033 395.033 :1() 1 0.000 0.000 395.033 395.033 CopyOrders.py:31(主要) 1 389.826 389.826 389.976 389.976 CopyOrders.py:67(扫描) 1 0.000 0.000 5.056 5.056 CopyOrders.py:88(副本) 1 0.000 0.000 0.000 0.000 getopt.py:56(getopt) 6 0.000 0.000 0.001 0.000 shutil.py:170(_copyfileobj_readinto) 6 0.000 0.000 1.346 0.224 shutil.py:202(_samefile) 18 0.000 0.000 1.493 0.083 shutil.py:220(_stat) 6 0.001 0.000 4.295 0.716 shutil.py:226(复制文件) 6 0.000 0.000 0.756 0.126 shutil.py:290(复制模式) 6 0.000 0.000 5.054 0.842 shutil.py:405(复制) 6 0.000 0.000 0.000 0.000 {内置方法_stat.S_IMODE} 6 0.000 0.000 0.000 0.000 {内置方法_stat.S_ISDIR} 6 0.000 0.000 0.000 0.000 {内置方法_stat.S_ISFIFO} 1 0.000 0.000 395.033 395.033 {内置方法 builtins.exec} 6 0.000 0.000 0.000 0.000 {内置方法 builtins.hasattr} 73 0.000 0.000 0.000 0.000 {内置方法 builtins.isinstance} 38 0.000 0.000 0.000 0.000 {内置方法 builtins.len} 6 0.000 0.000 0.000 0.000 {内置方法 builtins.min} 14 0.003 0.000 0.003 0.000 {内置方法 builtins.print} 12 2.180 0.182 2.180 0.182 {内置方法 io.open} 1 0.000 0.000 0.000 0.000 {内置方法 nt._getfullpathname} 1 0.000 0.000 0.000 0.000 {内置方法 nt._path_normpath} 6 0.012 0.002 0.012 0.002 {内置方法 nt.chmod} 49 0.000 0.000 0.000 0.000 {内置方法 nt.fspath} 1 0.149 0.149 0.149 0.149 {内置方法 nt.scandir} 36 2.841 0.079 2.841 0.079 {内置方法 nt.stat} 12 0.000 0.000 0.000 0.000 {内置方法 sys.audit} 12 0.019 0.002 0.019 0.002 {方法'出口'_io._IOBase' 对象} 6 0.000 0.000 0.000 0.000 {方法'出口' 的 'memoryview' 对象} 6 0.000 0.000 0.000 0.000 {“设置”对象的“添加”方法} 1 0.000 0.000 0.000 0.000 {“_lsprof.Profiler”对象的“禁用”方法} 36 0.000 0.000 0.000 0.000 {“str”对象的“查找”方法} 12 0.001 0.000 0.001 0.000 {'_io.BufferedReader' 对象的'readinto'方法} 30 0.000 0.000 0.000 0.000 {“str”对象的“替换”方法} 6 0.000 0.000 0.000 0.000 {“str”对象的“rstrip”方法} 6 0.000 0.000 0.000 0.000 {“_io.BufferedWriter”对象的“写入”方法}

【问题讨论】:

    标签: python python-3.x multithreading io multiprocessing


    【解决方案1】:

    由于您只对文件名感兴趣,而不对任何其他文件属性感兴趣,因此您不应使用 os.scandir 来承担构建具有所有文件属性的对象的开销。使用os.listdir 来只检索文件名列表。

    其次,您可以使用交替模式的正则表达式来更有效地搜索多个子字符串,因为 re 模块是用更快的 C 语言编写的。

    import re
    
    def scan(sourcedir:str, oset:set[str]) -> set[str]:
        regex = re.compile('|'.join(map(re.escape, oset)))
        return set(filter(regex.search, os.listdir(sourcedir)))
    

    请注意,您将 oset 参数键入为 set[str]|str,这没有什么意义,因为无法以一致的方式处理字符串容器和字符串。在我的示例中,我将其输入为 set[str]

    【讨论】:

    • 我会再试一次,但在我的测试中,listdir 比 scandir 慢一点。我添加了“|str”以停止显示一个愚蠢的 pylint 错误,指出 set[str] 与 set[str]|str 不兼容。这显然没有意义,但是...... pylint。我对吗?我以前没有尝试过 re,我对此持开放态度,但大部分时间都花在从网络共享中获取文件列表上,所以这就是我一直关注的重点。
    【解决方案2】:

    你可以试试glob

    我没有包含 300,000 个文件的目录来测试它,但我假设它会很快(几秒钟)。

    import glob
    
    sourcedir = r'path	oyouriles'
    oset = ['some','list','not','shown','in','your','code']
    
    found = []
    for ordr in oset:
    # Get a list of all files in the "sourcedir" directory with "ordr" in the filename
        files = [f for f in glob.glob(f"{sourcedir}*{ordr}*")]
        found.extend(files)
    
    print('
    '.join(found))
    
    

    【讨论】:

    • 从我看到的比较运行调用所需时间的来源来看,glob 比其他方法慢。我想这值得测试。
    【解决方案3】:

    我最终发现,无论我扫描多少文件,都不会超过较短的文件列表(很多)。所以我认为收集现有文件列表进行比较所花费的很长一段时间类似于索引目录。我将该工具用于更大的文件集。对于 onsies 和 twosies,我手动搜索。我想就是这样。

    【讨论】:

      猜你喜欢
      • 2015-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-02
      • 2014-09-25
      • 2015-03-24
      • 2021-05-29
      • 2015-02-23
      相关资源
      最近更新 更多