使用Python进行文件快速搜索(建立文件搜索索引)

您所在的位置:网站首页 如何快速台词搜索文件内容 使用Python进行文件快速搜索(建立文件搜索索引)

使用Python进行文件快速搜索(建立文件搜索索引)

2024-07-14 20:28| 来源: 网络整理| 查看: 265

基础搜索方法:

用 pathlib 库搜索文件用 Python 搜索文件时需要使用 pathlib 库的 glob() 函数和 rglob() 函数,glob() 函数可以实现基于文件名的搜索方法,rglob 函数可以实现基于扩展名的搜索方法。

from pathlib import Path base_dir = '/Users/edz/Desktop/' keywords = '**/*BBC*' # 遍历base_dir指向的目录下所有的文件 p = Path(base_dir) # 当前目录下包含BBC的所有文件名称 files = p.glob(keywords) # files的类型是迭代器 # 通过list()函数转换为列表输出 # print(list(files)) # xlsx结尾的文件 files2 = p.rglob('*.xlsx') print(list(files2)) # 遍历子目录和所有文件 files3 = p.glob('**/*') print(list(files3))

由于 glob() 进行匹配的是文件的路径和文件名称方式,如: “c:\somepath\to\filename_include_BBC_voice.exe” , 而我们进行文件搜索的时候一般会使用关键字,如“BBC”,因此在搜索时我们需要为关键字加上通配符的形式,如“BBC” 。

通配符是类似正则表达式的元字符的一种特殊符号,它不能用在正则表达式中,只能用在 glob(全称 global)匹配模式中。 在这里插入图片描述 rglob 函数是从文件路径末尾向前进行匹配的,这是它和 glob() 函数的主要区别, 基于 rglob() 函数的搜索顺序特点,经常被我们用于进行扩展名的搜索,比如说采用 rglob(’*.xlsx’) 就可以搜索所有的 xlsx 扩展名文件,要比使用 glob() 编写的模式匹配更简单,参数的含义也更清晰。

最后再看一下 glob() 和 rglob() 函数的返回值,有一点我需要提醒你:它们的执行结果是我们之前课程中没有接触过的一种新的数据类型,这种类型叫做“迭代器”。

提升搜索效率的两种方法

用 Python 的 pathlib 库实现文件搜索,只是在灵活性上比 Windows 默认的搜索更好,但是搜索效率上并不能带来任何提高。为了减少搜索的等待时间, 接下来,我就教你使用指定搜索路径和建立索引文件两个方法, 提高 pathlib 库的搜索效率。

指定搜索路径

我们先来看第一种,指定搜索路径。 我们需要通过三个步骤实现:

先生成配置文件,把要搜索的路径写入到配置文件中;

再编写读取配置文件和搜索的自定义函数,把配置文件中的路径读取出来,逐个目录搜索;

最后,将多个目录的搜索结果合并输出,便于你通过结果快速找到自己想要的文件。

先说第一步,怎么使用 Python 读取配置文件。以往我们会把要搜索的路径写入到变量,并把定义路径的变量名称放在代码前几行的位置,便于下次修改搜索目录的时候找到这个变量。但是对于代码工程稍微复杂的程序来说,往往会有多个代码文件,仍然不利于每次搜索的时候进行搜索路径的修改。新的方法,就是把变量放入到一个单独的文件中,这个文件被称作该代码的配置文件。

这种方法的好处是你修改搜索目录时不用打开代码文件。假设你的朋友也需要类似功能,那你就可以把代码和配置文件一起发给他,哪怕他完全不会 Python,也能使用你编写的程序实现高效搜索。

配置文件一般为文本文件。配置文件的格式,一般由软件作者基于软件的功能和自己的习惯来指定,不过也有通用的配置文件格式。

比如在 Windows 系统中,最常见的配置文件是扩展名为.ini 的文件,在今天这节课,我们就把.ini 文件格式作为配置文件的标准格式。.ini 文件格式包含三个部分,分别是节、参数和注释。格式如下:

节 [section] 参数 (键=值) name=value 注释 注释使用“;”分号表示。在分号后面的文字,直到该行结尾都全部为注解。 ;注释内容 #基于.ini 文件的格式,我把配置搜索路径的配置文件修改为如下: [work] ;工作文件保存路径 searchpath=/Users/edz,/tmp [game] ;娱乐文件保存路径 searchpath=/games,/movies,/music

在这段代码中,我设置了 work 和 game 两个“节”,分别代表工作和娱乐。这样设置的好处是,我可以根据不同的用途来搜索不同的目录。如果搜索时使用了更少的目录,也会相应减少搜索的等待时间。

另外,你会发现两个“节”中的参数我都指定成相同的名字 --searchpath,这样设置的好处是我将搜索范围从“工作”改为“娱乐”时,只需要在代码里修改搜索的“节”,不用修改搜索的参数。

除了“节”和“参数”,在配置文件中,你还应该关注我对参数 searchpath 设置值的方式,它的值是我想要进行搜索的路径范围,为了在程序中能够更方便得读取多个路径,我使用逗号来分隔多个路径。

找到 search.ini 文件完整路径之后,接下来需要读取并分析.ini 文件格式,Python 有实现这个功能的的库,它叫做 configparser 库,通过这个库你可以直接读取.ini 文件中的 searchpath 参数,不用通过 read() 函数读取文件内容,手动编写分析.ini 文件的脚本了。

import configparser import pathlib from pathlib import Path def read_dirs(ini_filename, section, arg): """ 通过ini文件名,节和参数取得要操作的多个目录 """ current_path = pathlib.PurePath(__file__).parent inifile = current_path.joinpath(ini_filename) # cf是类ConfigParser的实例 cf = configparser.ConfigParser() # 读取.ini文件 cf.read(inifile) # 读取work节 和 searchpath参数 return cf.get(section, arg).split(",") def locate_file(base_dir, keywords): p = Path(base_dir) files = p.glob(keywords) return list(files) dirs = read_dirs('search.ini', 'work', 'searchpath') # ['/Users/edz', '/tmp'] keywords = '**/*BBC*' # 定义存放查找结果的列表 result = [] # 从每个文件夹中搜索文件 for dir in dirs: files = locate_file(dir, keywords) result += files # 将PosixPath转为字符串 print( [str(r) for r in result] )

read_dirs() 函数实现了读取.ini 文件,并将返回的多个路径处理为列表类型。列表类型适合多组并列的数据,多个目录刚好可以使用列表这种数据类型来存放要搜索的目录名称。

locate_file() 函数通过代码的第 35 行循环功能,对每个目录进行了搜索,并将搜索的结果存入 result 变量。result 变量是一个列表数据类型,由于搜索到的文件可能包含多个匹配的文件路径,我需要将搜索到的结果依次存入 result 列表中,再继续搜索下一个目录,继续通过 append() 函数将结果放入列表,直到所有的目录搜索完成,整个搜索的程序才真正执行结束。

最后还有一点需要你注意,在进行路径处理的过程中,pathlib 库为了规避不同操作系统路径写法的差异,就把路径统一定义为 PosixPath() 对象。因此,你在使用这些路径的时候,需要先将 PosixPath 对象转换为字符串类型。我在代码最后一行通过 Python 内置函数 str() 函数把 PosixPath 对象逐个转换为字符串类型,并再次存入到列表当中。

建立索引文件

我们可以基于指定搜索路径的程序进行改造:先把配置文件目录下所有文件路径的保存方式由列表改为文件;再把搜索功能改为从文件搜索。

def locate_file(base_dir, keywords='**/*'): """ 迭代目录下所有文件 """ p = Path(base_dir) return p.glob(keywords) def write_to_db(): """ 写入索引文件 """ current_path = pathlib.PurePath(__file__).parent dbfile = current_path.joinpath("search.db") with open(dbfile, 'w', encoding='utf-8') as f: for r in result: f.write(f"{str(r)}\n") # 读取配置文件 dirs = read_dirs('search.ini', 'work', 'searchpath') # 遍历目录 result = [] for dir in dirs: for files in locate_file(dir): result.append(files) # 将目录写入索引文件 write_to_db()

在代码中我增加了 write_to_db() 函数,它在代码的第 16-18 行,我通过写入文件方式替代了写入列表的功能。同时,为了能遍历所有的目录,我还修改了 locate_file() 函数的第二个参数,将它改为“keywords='/*'”。通过这两处的修改,就把所有文件路径全部保存到 search.db 文件中了。**

search.db 的文件内容如下,这里记录了配置文件指定的所有目录下的所有文件路径:

/tmp/com.apple.launchd.kZENgZTtVz /tmp/com.google.Keystone /tmp/mysql.sock /tmp/com.adobe.AdobeIPCBroker.ctrl-edz /tmp/com.apple.launchd.kZENgZTtVz/Listeners /tmp/com.google.Keystone/.keystone_install_lock ... ... 从文本中搜索关键字 import pathlib import re keyword = "apple" # 获取索引文件路径 current_path = pathlib.PurePath(__file__).parent dbfile = current_path.joinpath("search.db") # 在索引文件中搜索关键字 with open(dbfile, encoding='utf-8') as f: for line in f.readlines(): if re.search(keyword, line): print(line.rstrip())

在代码中我利用正则表达式的 re.search() 搜索函数,以 keyword 变量作为搜索的关键字,对 search.db 索引文件的每一行进行了匹配,最后将符合关键字“apple”的文件路径和名称一起显示在屏幕上。

使用这种方式来搜索文件,要比使用操作系统自带的搜索工具快得多,因为我将原本 Windows 搜索硬盘上的文件所消耗的时间拆分成了两部分。一部分是 updatedb.py 建立索引的时间;一部分是从 search.db 索引文件查找关键字的时间。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3