1 背景
有时候,我们想不起自己记录的信息在哪个文件里,需要一个个打开文件查找,非常麻烦。
这时候,我们可以借助python,实现一键快速查找。
2 环境
Python 3.7.3 64-bit
tkinter
re
3 os.walk()
os.walk方法用于遍历目录和文件,简单易用,可以帮助我们高效的处理目录、文件方面的事情
os.walk方法语法格式如下:
os.walk(top=r"C:\Temp\TxGameDownload", topdown=True, οnerrοr=None, followlinks=False)
- top:你要遍历的目录地址,如C:\Temp\TxGameDownload
- topdown:可选(默认为True),为True则优先遍历top目录,否则优先遍历top的子目录
- onerror:可选(默认为None),Callable对象,需要异常时调用
- followlinks:可选(默认为False),为True则会遍历目录下的快捷方式实际所指向的目录(注:windows下不生效,followlinks依赖于os.path.isdir和os.path.islink,很可惜,在windows下快捷方式返回的都是False)
- 返回结果:返回的是一个包含三元组dirpath, dirnames, filenames的Directory tree generator
简单例子:
for root, dirs, files in os.walk(r"C:\Temp\TxGameDownload"):
for name in files:
print(os.path.join(root, name))
for name in dirs:
print(os.path.join(root, name))
4 快速查找主要代码
def get_file_data(self, file_path):
"""获取文件内容
:param file_path: 文件完整路径
"""
data = None
try:
f = open(file_path, mode="r", encoding="utf-8") # 尝试用utf8编码打开
data = f.read().splitlines() # 将文件内容读取为按行分隔的列表
f.close() # 关闭文件
except UnicodeDecodeError:
f = open(file_path, mode="r", encoding="gb18030") # 尝试用gb18030编码打开
data = f.read().splitlines() # 将文件内容读取为按行分隔的列表
f.close() # 关闭文件
return data
def find_text(
self,
dir,
file_name_pattern="*",
file_content_pattern="",
stdout=print,
stderr=print,
output_max=613
):
"""查找文件内容
:param dir: 待查找目录
:param file_name_pattern: 文件名模糊匹配
:param file_content_pattern: 待查找的文本内容
:param output_max: 字符串长度超过max值则不打印具体信息
"""
if file_content_pattern == "": stderr("请输入查找内容!"); return # 查找内容不能为空
if file_name_pattern == "": file_name_pattern = "*" # 文件名匹配为空则查找目录下所有文件
file_name_pattern = r"^{}$".format(file_name_pattern.replace("*", ".*")) # 转换成正则表达式
file_content_pattern = r"{}".format(file_content_pattern.replace("*", ".*")) # 转换成正则表达式
self.stop = False # 初始化强制停止标记
self.find_info = dict() # 初始化查找信息
for root, dirs, files in os.walk(dir): # 遍历文件
if self.stop: # 用于控制手动强制停止查找
break
for file in files:
if self.stop: # 用于控制手动强制停止查找
break
file_path = os.path.abspath(os.path.join(root, file)) # 文件完整路径
if re.search(file_name_pattern, file, re.I): # 判断文件名是否满足模糊匹配规则
try:
data = self.get_file_data(file_path=file_path) # 获取文件数据
except UnicodeDecodeError:
stderr(file_path, str(e)) # 输出异常信息(编码问题)
continue
except PermissionError as e:
stderr(file_path, str(e)) # 输出异常信息(权限问题)
continue
row_id = 0 # 行号
for line in data: # 遍历每一行数据
row_id += 1 # 行号
if re.search(file_content_pattern, line, re.I): # 判断是否为要查找的内容
self.find_info[file_path] = self.find_info.get(file_path, 0) + 1 # 记录查找到的信息
stdout( # 输出查找到的信息
file_path,
"第" + str(row_id) + "行",
line if len(line) <= output_max else "……"
)
5 tkinter封装
class ToplevelFileFindText(EToplevel):
"""一个顶级窗口(类似弹窗),用于一键查找文件内容
"""
FIND_START_DESC = "开始查找"
FIND_END_DESC = "结束查找"
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master, cnf, **kw)
self.dir_to_find = None # 待查找目录
self.button_ask_dir = self.create_button_ask_dir() # 创建按钮(点击后弹出文件夹选择框)
self.button_ask_dir.grid(row=0, column=0, sticky=tk.NSEW)
self.dir = StringVar()
self.dir.set("")
self.label_dir = Label(self, textvariable=self.dir) # 创建标签,用于显示所选文件夹路径
self.label_dir.grid(row=0, column=1, sticky=tk.W)
self.label_file_name_pattern = Label(self, text="文件名称匹配") # 创建"文件名称匹配"标签
self.label_file_name_pattern.grid(row=1, column=0, sticky=tk.NSEW)
self.file_name_pattern = StringVar()
self.file_name_pattern.set("*.py")
self.entry_file_name_pattern = Entry(self, textvariable=self.file_name_pattern) # 创建"文件名称匹配"输入框
self.entry_file_name_pattern.grid(row=1, column=1, sticky=tk.NSEW)
self.label_file_content_pattern = Label(self, text="文件内容匹配") # 创建"文件内容匹配"标签
self.label_file_content_pattern.grid(row=2, column=0, sticky=tk.NSEW)
self.file_content_pattern = StringVar()
self.file_content_pattern.set("import")
self.entry_file_content_pattern = Entry(self, textvariable=self.file_content_pattern) # 创建"文件内容匹配"输入框
self.entry_file_content_pattern.grid(row=2, column=1, sticky=tk.NSEW)
self.button_find_start = self.create_button_find_start() # 创建一键查找按钮
self.button_find_start.grid(row=3, column=0, sticky=tk.NSEW)
self.button_find_end = self.create_button_find_end() # 创建查找终止按钮
self.button_find_end.grid(row=4, column=0, sticky=tk.NSEW)
self.file_tool = File() # 实例化文件查找工具
6 演示效果
7 完整代码
github.com/TheUncleWhoGrowsBeans