在任意目录下查找需要的文件如何操作呢?

其实很简单, WIN+E 【桌面计算机】- 右上角“搜索 计算机”

这个就是Windows自带的文件搜索功能。自己做一个文件搜索的应该应该也挺好玩的。

知识要点:

os.walk 函数
方法用于通过在目录树种游走输出在目录中的文件名,向上或者向下深度遍历目录。
os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])

参数

  • top -- 根目录下的每一个文件夹(包含它自己), 产生3-元组 (dirpath, dirnames, filenames)【文件夹路径, 文件夹名字, 文件名】。

  • topdown --可选,为True或者没有指定, 一个目录的的3-元组将比它的任何子文件夹的3-元组先产生 (目录自上而下)。如果topdown为 False, 一个目录的3-元组将比它的任何子文件夹的3-元组后产生 (目录自下而上)。

  • onerror -- 可选,是一个函数; 它调用时有一个参数, 一个OSError实例。报告这错误后,继续walk,或者抛出exception终止walk。

  • followlinks -- 设置为 true,则通过软链接访问目录。

 例子:

import os
for root, dirs, files in os.walk(".", topdown=False):
for name in files:
print(os.path.join(root, name))
for name in dirs:
print(os.path.join(root, name))

先从根目录进行遍历,读取跟目录的文件夹和文件。以根目录第一个子目录为新的根目录,读取其文件夹和文件。第一个子文件夹为根目录,读取文件夹和文件,直到结束。

下面,我们开始编写,新的应用

一.UI

对样式或审美不是很敏感(主要是功能),所以对于UI随心所遇的设计,一下为UI代码:

class MainWidgetUI(QDialog):
def __init__(self, parent=None):
super(MainWidgetUI, self).__init__(parent)
self.setWindowIcon(QtGui.QIcon("favicon.ico"))
self.setWindowOpacity(0.85) # 透明度
self.setWindowTitle('查询文件')
self.directory = '' # 跟目录
self.mainLayout = QVBoxLayout() # 水平布局
# Find 文件布局
self.topgroupBox = QGroupBox("任意右键选择查询目录")
self.topLayout = QHBoxLayout(self.topgroupBox)
self.lineEdit = QLineEdit('', self.topgroupBox)
self.lineEdit.setPlaceholderText('如:chrome.exe, 多个 ; 分割')
self.searchBtn = QPushButton(QtGui.QIcon("favicon.ico"), '查询', self.topgroupBox)
self.topLayout.addWidget(self.lineEdit)
self.topLayout.addWidget(self.searchBtn) # 输出文件路径布局
self.bottgroupBox = QGroupBox('文件路径')
self.bottLayout = QVBoxLayout(self.bottgroupBox) # 水平布局
self.ListWidget = QListWidget(self.bottgroupBox)
self.bottLayout.addWidget(self.ListWidget) # mainLayout 布局
self.mainLayout.addWidget(self.topgroupBox)
self.mainLayout.addWidget(self.bottgroupBox)
self.setLayout(self.mainLayout) self.lineEdit.setFocus() # 得到焦点
# 搜索框样式
self.lineEdit.setStyleSheet(
"QLineEdit{background-color:green;color:menubar;font-size:12px;background-image:url(search.png);}") if __name__ == "__main__":
app = QApplication(sys.argv)
main_widget = MainWidgetUI()
main_widget.show()
sys.exit(app.exec_())

UI效果:

当UI整完了后,发现个问题,如何选择要搜索目录呢,Windows自带的是整个硬盘搜索,这样目录太大,搜索时间太长,我们要的效果是将搜索的目录指定到某个盘或某个盘里面的某个文件夹。

想到了个办法,在UI中任意右键选择要搜索的目录:

    self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.rightHandButton) # 任意地方右键 选择跟目录 # 任意地方右键
def rightHandButton(self):
self.directory = QFileDialog.getExistingDirectory(self, "请选择根目录", 'c:\\')
self.topgroupBox.setTitle("查询根目录:" + str(self.directory))

二.SearchIndex

这一步就用os.walk查询文件,我们把这个功能封装正一个方法:

    def search_files(self, directory, patterns='*', single_level=False, yield_folders=False):
# 将模式从字符串中取出放入列表中
patterns = patterns.split(';')
for path, subdirs, files in os.walk(directory):
if yield_folders:
files.extend(subdirs)
files.sort()
for name in files:
for pattern in patterns:
if fnmatch.fnmatch(name, pattern):
yield os.path.join(path, name)
break
if single_level:
break

问题又来了,当点击查询按钮执行查找文件时,UI直接都卡死了

恍然也!查询文件的方法堵塞了UI主进程,所以我们用开启一个线程

# 线程查询类
class TheadingFindFile(QThread):
resultSearchSignal = pyqtSignal(list) # 声明一个带列表结果的参数信号 def __init__(self, tuple):
super(TheadingFindFile, self).__init__()
self.searchTuple = tuple # 元组? def run(self):
result = [] # 列表
files = self.search_files(self.searchTuple[0], self.searchTuple[1], False, False)
for file in files:
result.append(file)
if not result:
result = ['无查询结果']
try:
self.resultSearchSignal.emit(result) # 发射信号
except Exception as e:
print(e) # 检查一个目录,后者某个包含子目录的目录树,并根据某种模式迭代所有文件
# patterns如:*.html,若大小写敏感可写*.[Hh][Tt][Mm][Ll]
# single_level 为True表示只检查第一层
# yield_folders 表示是否显示子目录,为False只遍历子目录中的文件,
# 但不返回字母名
def search_files(self, directory, patterns='*', single_level=False, yield_folders=False):
# 将模式从字符串中取出放入列表中
patterns = patterns.split(';')
for path, subdirs, files in os.walk(directory):
if yield_folders:
files.extend(subdirs)
files.sort()
for name in files:
for pattern in patterns:
if fnmatch.fnmatch(name, pattern):
yield os.path.join(path, name)
break
if single_level:
break

三.完善应用

在上一步中,尽管堵塞了UI进程,但文件少的时候也是可以完成搜索呈现在QListWidget中,作为一个严谨的***, 我们要将产品做到尽量的完美!

所以我们要做提交验证、开启查询线程防止UI堵塞、查询中禁止再次点击查询按钮、QListWidget的中的数据要能打开改目录,所以第三步,就是完善应用。

在查询按钮点击后,我们判断数据是否填写

self.ListWidget.clear()  # 清空ListWidget数据
inputs = self.lineEdit.text()
if inputs == '':
QMessageBox.warning(self, '查询提示', '输入的查询文件名关键字不能为空', QMessageBox.Yes)
return False
if self.directory == '':
QMessageBox.warning(self, '查询提示', '请任意右键选择查询的跟目录', QMessageBox.Yes)
return False

验证完成后,开启查询线程:

        try:
# 在 实例化类与connect、start 直接不能打印任何东西,不然会报错
senderData = (self.directory, self.lineEdit.text())
self.Theading = TheadingFindFile(senderData)
self.Theading.resultSearchSignal.connect(self.updateResult) # 连接信号。 TheadingFindFile在线程状态结果后emit发射信号
self.Theading.start() # 线程开始 except Exception as e:
print(e)

别急!我们应该在加一个查询按钮按下后的特效,因为查询会堵塞UI进程,相同的我想做一个每秒显示一个点点点的效果也会堵塞进程。【不用问,我已经试过的】,所以也开启了一个点点点的效果进程:

# 线程查询效果类
class TheadingSearchBtnNet(QThread):
resultSearchBtnNetSignal = pyqtSignal(str) # 声明一个带列表结果的参数信号 def __init__(self, str):
super(TheadingSearchBtnNet, self).__init__()
self.searchTuple = str # 设置status 的状态值, 1 为可执行,0:停止执行
def setVal(self, st):
self.st = st
self.start() def run(self):
i = 5
while True:
Dot = ''
if i <= 5:
for l in range(0, 5):
time.sleep(1)
Dot += str('.')
if self.st == 1: # 可执行
self.resultSearchBtnNetSignal.emit(str(Dot)) # 发射信号
i += 1
else:
i = 0

查询中点点点效果:

还有一个就是在ListWidget中呈现的路径,做了一个双击打开文件所在目录的功能,

    # List路径列表双击事件
def doubleClickListPath(self):
text = self.ListWidget.currentItem().text() # 获取当前Item的text
text = text.replace('/', '\\')
if text != '无查询结果':
os.system(r'explorer /select,' + str(text)) # 打开文件并选中文件

使用subprocess.Popen(file) 只能打开文件,使用explorer /select , file  可以用Windows自带的文件管理器打开文件的所在目录,并选中该文件。其实这个explorer直接可以在命令行CMD直接打开。

四.完整代码及效果

完整代码:

# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import QtGui
import os, sys, fnmatch
import time class MainWidgetUI(QDialog):
def __init__(self, parent=None):
super(MainWidgetUI, self).__init__(parent)
self.setWindowIcon(QtGui.QIcon("favicon.ico"))
self.setWindowOpacity(0.85) # 透明度
self.setWindowTitle('查询文件')
self.directory = '' # 跟目录
self.mainLayout = QVBoxLayout() # 水平布局
# Find 文件布局
self.topgroupBox = QGroupBox("任意右键选择查询目录")
self.topLayout = QHBoxLayout(self.topgroupBox)
self.lineEdit = QLineEdit('', self.topgroupBox)
self.lineEdit.setPlaceholderText('如:chrome.exe, 多个 ; 分割')
self.searchBtn = QPushButton(QtGui.QIcon("favicon.ico"), '查询', self.topgroupBox)
self.topLayout.addWidget(self.lineEdit)
self.topLayout.addWidget(self.searchBtn) # 输出文件路径布局
self.bottgroupBox = QGroupBox('文件路径')
self.bottLayout = QVBoxLayout(self.bottgroupBox) # 水平布局
self.ListWidget = QListWidget(self.bottgroupBox)
self.bottLayout.addWidget(self.ListWidget) # mainLayout 布局
self.mainLayout.addWidget(self.topgroupBox)
self.mainLayout.addWidget(self.bottgroupBox)
self.setLayout(self.mainLayout) self.searchBtn.clicked.connect(self.searchDef) # 查询事件
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.rightHandButton) # 任意地方右键 选择跟目录
self.ListWidget.itemDoubleClicked.connect(self.doubleClickListPath) # List路径列表双击事件
self.lineEdit.setFocus() # 得到焦点
# 搜索框样式
self.lineEdit.setStyleSheet(
"QLineEdit{background-color:green;color:menubar;font-size:12px;background-image:url(search.png);}") self.Theading2 = TheadingSearchBtnNet("查询")
self.Theading2.resultSearchBtnNetSignal.connect(self.searchBtnText) # 连接信号。 TheadingFindFile在线程状态结果后emit发射信号 # self.lineEdit.setText('chrome.exe;readme.txt')
# self.ListWidget.addItem("C:\\Program Files\\7-Zip/7z.exe")
# self.ListWidget.addItem("bb")
# self.ListWidget.addItem("E:\\Program Files/java") # 显示查询按钮点点点效果
def searchBtnText(self, strings):
self.searchBtn.setText("查询" + str(strings)) # List路径列表双击事件
def doubleClickListPath(self):
text = self.ListWidget.currentItem().text() # 获取当前Item的text
text = text.replace('/', '\\')
if text != '无查询结果':
os.system(r'explorer /select,' + str(text)) # 打开文件并选中文件 # 任意地方右键
def rightHandButton(self):
self.directory = QFileDialog.getExistingDirectory(self, "请选择根目录", 'c:\\')
self.topgroupBox.setTitle("查询根目录:" + str(self.directory)) # 查询BTN 按钮
def searchDef(self):
self.ListWidget.clear() # 清空ListWidget数据
inputs = self.lineEdit.text()
if inputs == '':
QMessageBox.warning(self, '查询提示', '输入的查询文件名关键字不能为空', QMessageBox.Yes)
return False
if self.directory == '':
QMessageBox.warning(self, '查询提示', '请任意右键选择查询的跟目录', QMessageBox.Yes)
return False
self.searchBtn.setDisabled(True)
self.Theading2.setVal(1) # 查询点点点效果线程开始
try:
# 在 实例化类与connect、start 直接不能打印任何东西,不然会报错
senderData = (self.directory, self.lineEdit.text())
self.Theading = TheadingFindFile(senderData)
self.Theading.resultSearchSignal.connect(self.updateResult) # 连接信号。 TheadingFindFile在线程状态结果后emit发射信号
self.Theading.start() # 线程开始 except Exception as e:
print(e) # 返回响应的参数
def updateResult(self, resultData):
self.searchBtn.setDisabled(False)
self.searchBtn.setText('查询')
self.Theading2.setVal(0) # 停止执行
for data in resultData:
self.ListWidget.addItem(data) # 线程查询类
class TheadingFindFile(QThread):
resultSearchSignal = pyqtSignal(list) # 声明一个带列表结果的参数信号 def __init__(self, tuple):
super(TheadingFindFile, self).__init__()
self.searchTuple = tuple # 元组? def run(self):
result = [] # 列表
files = self.search_files(self.searchTuple[0], self.searchTuple[1], False, False)
for file in files:
result.append(file)
if not result:
result = ['无查询结果']
try:
self.resultSearchSignal.emit(result) # 发射信号
except Exception as e:
print(e) # 检查一个目录,后者某个包含子目录的目录树,并根据某种模式迭代所有文件
# patterns如:*.html,若大小写敏感可写*.[Hh][Tt][Mm][Ll]
# single_level 为True表示只检查第一层
# yield_folders 表示是否显示子目录,为False只遍历子目录中的文件,
# 但不返回字母名
def search_files(self, directory, patterns='*', single_level=False, yield_folders=False):
# 将模式从字符串中取出放入列表中
patterns = patterns.split(';')
for path, subdirs, files in os.walk(directory):
if yield_folders:
files.extend(subdirs)
files.sort()
for name in files:
for pattern in patterns:
if fnmatch.fnmatch(name, pattern):
yield os.path.join(path, name)
break
if single_level:
break # 线程查询效果类
class TheadingSearchBtnNet(QThread):
resultSearchBtnNetSignal = pyqtSignal(str) # 声明一个带列表结果的参数信号 def __init__(self, str):
super(TheadingSearchBtnNet, self).__init__()
self.searchTuple = str # 设置status 的状态值, 1 为可执行,0:停止执行
def setVal(self, st):
self.st = st
self.start() def run(self):
i = 5
while True:
Dot = ''
if i <= 5:
for l in range(0, 5):
time.sleep(1)
Dot += str('.')
if self.st == 1: # 可执行
self.resultSearchBtnNetSignal.emit(str(Dot)) # 发射信号
i += 1
else:
i = 0 if __name__ == "__main__":
app = QApplication(sys.argv)
main_widget = MainWidgetUI()
main_widget.show()
sys.exit(app.exec_())

打包程序为exe:

if __name__ == '__main__':
from PyInstaller import __main__
params = ['-F','-w', '--icon=favicon.ico','--noupx', 'mainFindFiles.py']
__main__.run(params)

效果:

Pyqt walk 在Windows查找文件的更多相关文章

  1. Windows 查找txt后缀 文件复制

    Windows 查找文件 并且复制目录 for /f "delims==" %a in ('dir /b /s F:\F\*.TXT')do copy /-y "%a&q ...

  2. windows系统查找文件-通配符的使用

    在windows中可以使用通配符“* ”.“? ”查找文件.对于相同字符开头的单词和相同字符结尾的单词可以用“<”和“ >”通配符查找单词.1.如果要查找: 任意单个字符 :键入 ? 例如 ...

  3. Windows API 文件处理

    CloseHandle 关闭一个内核对象.其中包括文件.文件映射.进程.线程.安全和同步对象等 CompareFileTime 对比两个文件的时间 CopyFile 复制文件 CreateDirect ...

  4. shell脚本实现查找文件夹下重复的文件,并提供删除功能

    Windows下有软件FindDupFile,可以搜索指定目录及其下子目录,列出所有内容完全相同的文件(文件名可能不同),然后由用户选择删除重复的文件. 然而shell脚本却可以使用几行的命令完成与此 ...

  5. python——根据电子表格的数据自动查找文件

    最近刚接触python,找点小任务来练练手,希望自己在实践中不断的锻炼自己解决问题的能力. 经理最近又布置了一个很繁琐的任务给我:有一项很重大的项目做完了,但是要过审计(反正就是类似的审批之类的事情) ...

  6. windows 下文件的高级操作

    本文主要说明在Windows下操作文件的高级方法,比如直接读写磁盘,文件的异步操作,而文件普通的读写方式在网上可以找到一大堆资料,在这也就不再进行专门的说明. 判断文件是否存在 在Windows中并没 ...

  7. C++用 _findfirst 和 _findnext 查找文件

    一.这两个函数均在io.h里面.   二.首先了解一下一个文件结构体: struct _finddata_t {     unsigned    attrib;     time_t      tim ...

  8. Python查找文件

    1. 利用字符串的前缀和后缀匹配查找文件 str.startswith() star.endswith() 2.使用fnmatch fnmatch              判断文件名是否符合特定模式 ...

  9. 如何使用Windows Library文件进行持久化

    前言 想象一下,假设在你不知道的情况下,攻击者在你的计算机上放置了一个恶意文件.每当你访问桌面上某个文件夹时(例如Documents文件夹),都会执行一次该文件.这样的场景,通过利用一种鲜为人知的持久 ...

随机推荐

  1. B. Vova and Trophies 字符串预处理+思维+贪心

    题意:给出一个字符串 只有G和S  可以交换任意两个位置的字符一次 问 最长的G的长度是多少 思路:预处理字符串 把相同的G粘成一个G 记一下数量  字符串变为 GSSGSGGSGSSG 相邻有一个S ...

  2. Codeforces Round #513 总结

    首次正式的$Codeforces$比赛啊,虽然滚粗了,然而终于有$rating$了…… #A  Phone Numbers 签到题,然而我第一次写挂了(因为把11看成8了……) 只需要判断一下有多少个 ...

  3. Codeforces Round #530 (Div. 2) C D

    C: *可以保留删除或者增加 ? 保留或者删除 #include<bits/stdc++.h> using namespace std; int main(){ string s; int ...

  4. luoguP4841 城市规划

    题意: 求n个点的无相连通图的个数.有编号 思路一: 黏博客 至于为什么除以k!:(没有博客中说的那么简单) 实际上, 对于一个n的用k个自然数的拆分,每一个拆分的贡献是: $\frac{n!*\Pi ...

  5. 从线程池到synchronized关键字详解

    线程池 BlockingQueue synchronized volatile 前段时间看了一篇关于"一名3年工作经验的程序员应该具备的技能"文章,倍受打击.很多熟悉而又陌生的知识 ...

  6. python集合(set)的运算

    1.交集 In [1]: a = {1,2,3,4} In [2]: b = {3,4,5,6} In [3]: a & b Out[3]: {3, 4} In [4]: a.intersec ...

  7. MySQL_关于索引空间的的一些记录

    一.清理普通索引占用的空间 问:对表中存在的k列(非主键)的普通索引执行以下重建操作,有什么影响? alter table T drop index k; alter table T add inde ...

  8. CAS实现单点登录

    1.简介 SSO单点登录 在多个相互信任的系统中,用户只需要登录一次就可以访问其他受信任的系统. 新浪微博与新浪博客是相互信任的应用系统. *当用户首次访问新浪微博时,新浪微博识别到用户未登录,将请求 ...

  9. tomcat无法正常关闭问题分析及解决

    问题描述 通常,我们都会直接使用tomcat提供的脚本执行关闭操作,如下: # sh bin/shutdown.sh Using CATALINA_BASE: /usr/local/apache-to ...

  10. SQL注入关联分析

    在Web攻防中,SQL注入绝对是一个技能的频繁项,为了技术的成熟化.自动化.智能化,我们有必要建立SQL注入与之相关典型技术之间的关联规则.在分析过程中,整个规则均围绕核心词进行直线展开,我们简单称之 ...