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

其实很简单, 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. 10.1 ES6 的新增特性以及简单语法

    ES6 的新增特性以及简单语法  let 和 const 模板字符串 箭头函数 对象单体模式 es6面向对象 模块化  let 和 const 之前一直用 var 来声明变量,ES6 新增 let 和 ...

  2. Magento 2 Theme Ultimate Guide - 如何创建Magento 2主题终极指南

    Magento 2 Theme Ultimate Guide - 如何创建Magento 2主题基础指南 在Magento 2中管理和设置主题的方式有很多改进.Magento 1.9中引入的theme ...

  3. CQOI2018异或序列 [莫队]

    莫队板子 用于复习 #include <cstdio> #include <cstdlib> #include <algorithm> #include <c ...

  4. svn客户端更改用户名

    你是用的小乌龟做客户端吗?在文件夹里点右键,选择TortoiseSVN->Setings->SavedData里面有个authentication data,点击后面的Clear就好了下次 ...

  5. vue---slot,slot-scoped,以及2.6版本之后插槽的用法

    slot 插槽 ,是用在组件中,向组件分发内容.它的内容可以包含任何模板代码,包括HTML. vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令).它取 ...

  6. 记一次504 Gateway Time-out

    使用curl请求是超时,查了下资料原来是端口被占用,造成了死锁,记录下 首先要知道为什么会出现死锁? 在我们访问页面的时候这个端口进程就已经被使用,当我们再在页面中curl请求其他页面因为没有其他的端 ...

  7. 驱动调试(一)-printk

    目录 驱动调试(一)-printk 引入 框架 入口console_setup add_preferred_console register_console s3c24xx_serial_initco ...

  8. postgreSql 常用操作总结

    0. 启动pgsl数据库 pg_ctl -D /xx/pgdata start 1. 查看pgsl版本 pg_ctl --version 1. 命令行登录数据库 psql -U username -d ...

  9. SSH框架之hibernate《三》

    Hibernate03     一.多表设计         1.1多表设计的总则             问题:我们为什么要学习多表映射?             答:                ...

  10. SQLServer数据库文件由高版本向低版本转换

    这个只能用2012的生成脚本功能,在高级里面把脚本兼容设置成2008,并且选择生成架构和数据(默认是只有架构)拿这个脚本在2008上跑一次就行了 sqlserver 中使用sqlcmd 执行*.sql ...