提问人:Just Works 提问时间:1/10/2023 最后编辑:Just Works 更新时间:2/7/2023 访问量:76
在非常大的目录中搜索名称中包含文本的文件
Search a very large directory for a file containing text in it's name
问:
我有一个网络共享,其中包含大约 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(ISDIR) 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(abspath) 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' 对象的方法'exit'} 6 0.000 0.000 0.000 0.000 {“memoryview”对象的方法“exit”} 6 0.000 0.000 0.000 0.000 {“设置”对象的方法“add”} 1 0.000 0.000 0.000 0.000 {方法 'disable' of '_lsprof.探查器对象} 36 0.000 0.000 0.000 0.000 {'str' 对象的方法 'find'} 12 0.001 0.000 0.001 0.000 {'_io.BufferedReader 的对象} 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 的 'write' 方法。BufferedWriter 的对象}
答:
你可以试试 glob
我没有一个包含 300,000 个文件的目录来测试它,但我假设它会很快(几秒钟)。
import glob
sourcedir = r'path\to\your\files'
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('\n'.join(found))
评论
由于您只对文件名感兴趣,而对任何其他文件属性不感兴趣,因此不应使用文件来产生具有所有文件属性的构建对象的开销。请改用以仅检索文件名列表。os.scandir
os.listdir
其次,您可以使用交替模式的正则表达式来更有效地搜索多个子字符串,因为该模块是用速度快得多的 C 语言编写的。re
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]
评论
我最终发现,无论我扫描多少个文件,它只需要一个较短的文件列表(很多)。因此,我认为收集要比较的现有文件列表所花费的很长时间类似于索引目录。我正在将该工具用于更大的文件集。对于 onsies 和 twosies,我手动搜索。我想就是这样。
评论