吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5910|回复: 51
收起左侧

[原创工具] Windows 本地搜索小工具,不喜勿喷,仅供分享

  [复制链接]
薄了微凉 发表于 2025-4-1 12:29
本帖最后由 薄了微凉 于 2025-4-1 12:32 编辑

因个人资料过多,弄了个小工具,方便搜索,另存新文件,保留原始文件,不喜勿喷,只是分享,按需自取,

PS:如有违规,请联系删帖,请管理大大们不要直接给个违规哈


## 功能特点
- 快速搜索文件名
- 实时显示搜索结果
- 支持文件大小和修改时间显示
- 双击直接打开文件
- 支持选择搜索目录
- 支持关键词联合搜索(中英文 逗号,分号,空格等分隔符)
- 支持搜索结果类型选择切换
- 支持搜索过程中终止搜索
- 支持导出搜索结果列表
- 支持批量复制搜索结果
- 支持重置清空搜索条件、搜索结果
- 过滤缓存文件和特定文件类型:'cache', 'temp', '.tmp', '.wps', '.lnk', '.et'
- 支持的分隔符:',', '、', ',', ';', ';', '/', '\\', '|', '|'

运行页面

运行页面

联合搜索

联合搜索

批量复制

批量复制


Python

[Python] 纯文本查看 复制代码
import os
import glob
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from openpyxl import Workbook
from pathlib import Path
import threading
import queue

class FileSearchApp:
    def __init__(self, root):
        self.root = root
        self.root.title('吾爱破解论坛本地文件搜索')
        self.root.geometry('1250x600')
        
        # 创建搜索框和按钮
        self.search_frame = ttk.Frame(root)
        self.search_frame.pack(fill='x', padx=5, pady=5)
        
        self.path_label = ttk.Label(self.search_frame, text='搜索路径:')
        self.path_label.pack(side='left')
        
        self.path_var = tk.StringVar(value=str(Path.home()))
        self.path_entry = ttk.Entry(self.search_frame, textvariable=self.path_var, width=20)
        self.path_entry.pack(side='left', padx=5)
        
        self.browse_btn = ttk.Button(self.search_frame, text='浏览', command=self.browse_directory)
        self.browse_btn.pack(side='left')
        
        self.search_label = ttk.Label(self.search_frame, text='搜索关键词:')        
        self.search_label.pack(side='left', padx=(10, 0))
        
        self.keyword_var = tk.StringVar()
        self.keyword_entry = ttk.Entry(self.search_frame, textvariable=self.keyword_var, width=25)
        self.keyword_entry.insert(0, '支持空格、逗号、分号等分隔符')
        self.keyword_entry.config(foreground='gray')
        self.keyword_entry.bind('<FocusIn>', self.on_keyword_entry_focus_in)
        self.keyword_entry.bind('<FocusOut>', self.on_keyword_entry_focus_out)
        self.keyword_entry.pack(side='left', padx=5)
        
        self.type_label = ttk.Label(self.search_frame, text='文件类型:')
        self.type_label.pack(side='left', padx=(10, 0))
        
        self.file_types = {
            '全部': '*',
            '文档': ['.txt', '.doc', '.docx', '.pdf', '.xls', '.xlsx', '.ppt', '.pptx'],
            '图片': ['.jpg', '.jpeg', '.png', '.gif', '.bmp'],
            '视频': ['.mp4', '.avi', '.mkv', '.mov', '.wmv'],
            '音频': ['.mp3', '.wav', '.flac', '.m4a', '.wma'],
            '压缩包': ['.zip', '.rar', '.7z', '.tar', '.gz'],
            '代码': ['.py', '.js', '.java', '.cpp', '.c', '.h', '.cs', '.html', '.css', '.php', '.go', '.rs', '.rb', '.swift']
        }
        
        self.type_var = tk.StringVar(value='全部')
        self.type_combobox = ttk.Combobox(self.search_frame, textvariable=self.type_var, values=list(self.file_types.keys()), state='readonly', width=10)
        self.type_combobox.pack(side='left', padx=5)
        self.type_combobox.bind('<<ComboboxSelected>>', self.on_type_changed)
        
        self.search_btn = ttk.Button(self.search_frame, text='搜索', command=self.start_search)
        self.search_btn.pack(side='left')
        
        self.stop_btn = ttk.Button(self.search_frame, text='停止', command=self.stop_search, state='disabled')
        self.stop_btn.pack(side='left', padx=5)
        
        self.export_btn = ttk.Button(self.search_frame, text='导出列表', command=self.export_results)
        self.export_btn.pack(side='left', padx=5)
        
        self.reset_btn = ttk.Button(self.search_frame, text='重置', command=self.reset_search)
        self.reset_btn.pack(side='left', padx=5)
        
        # 创建结果显示区域
        self.result_frame = ttk.Frame(root)
        self.result_frame.pack(fill='both', expand=True, padx=5, pady=5)
        
        # 创建Treeview来显示搜索结果
        self.tree = ttk.Treeview(self.result_frame, columns=('name', 'path', 'size', 'modified'), show='headings', selectmode='extended')
        

        
        # 添加批量复制按钮
        self.batch_copy_btn = ttk.Button(self.search_frame, text='批量复制', command=self.batch_copy_files)
        self.batch_copy_btn.pack(side='left', padx=5)
        
        # 添加排序功能
        self.sort_order = {'name': True, 'path': True, 'size': True, 'modified': True}  # True表示升序
        
        def sort_column(col):
            items = [(self.tree.set(item, col), item) for item in self.tree.get_children('')]
            
            # 特殊处理文件大小排序
            if col == 'size':
                def size_to_bytes(size_str):
                    units = {'B': 1, 'KB': 1024, 'MB': 1024**2, 'GB': 1024**3, 'TB': 1024**4}
                    size, unit = size_str.split()
                    return float(size) * units[unit.strip()]
                items = [(size_to_bytes(self.tree.set(item, col)), item) for item in self.tree.get_children('')]
            
            # 特殊处理修改时间排序
            elif col == 'modified':
                from datetime import datetime
                items = [(datetime.strptime(self.tree.set(item, col), '%Y-%m-%d %H:%M'), item) 
                         for item in self.tree.get_children('')]
            
            # 根据当前排序顺序决定是升序还是降序
            items.sort(reverse=not self.sort_order[col])
            self.sort_order[col] = not self.sort_order[col]
            
            # 重新插入排序后的项
            for index, (val, item) in enumerate(items):
                self.tree.move(item, '', index)
            
            # 更新表头箭头
            for c in ('name', 'path', 'size', 'modified'):
                # 获取当前表头文本(不包含箭头)
                current_text = self.tree.heading(c)['text'].split(' ')[0]
                # 只在当前排序列显示箭头
                if c == col:
                    self.tree.heading(c, text=current_text + (' ↑' if self.sort_order[c] else ' ↓'))
                else:
                    self.tree.heading(c, text=current_text)
        
        self.tree.heading('name', text='文件名', command=lambda: sort_column('name'))
        self.tree.heading('path', text='路径', command=lambda: sort_column('path'))
        self.tree.heading('size', text='大小', command=lambda: sort_column('size'))
        self.tree.heading('modified', text='修改时间', command=lambda: sort_column('modified'))
        
        self.tree.column('name', width=200)
        self.tree.column('path', width=300)
        self.tree.column('size', width=100)
        self.tree.column('modified', width=150)
        
        # 添加垂直滚动条
        self.vsb = ttk.Scrollbar(self.result_frame, orient='vertical', command=self.tree.yview)
        # 添加水平滚动条
        self.hsb = ttk.Scrollbar(self.result_frame, orient='horizontal', command=self.tree.xview)
        self.tree.configure(yscrollcommand=self.vsb.set, xscrollcommand=self.hsb.set)
        
        # 使用grid布局管理器
        self.tree.grid(row=0, column=0, sticky='nsew')
        self.vsb.grid(row=0, column=1, sticky='ns')
        self.hsb.grid(row=1, column=0, sticky='ew')
        
        # 配置grid权重
        self.result_frame.grid_rowconfigure(0, weight=1)
        self.result_frame.grid_columnconfigure(0, weight=1)
        
        # 创建右键菜单
        self.context_menu = tk.Menu(self.root, tearoff=0)
        self.context_menu.add_command(label='打开文件', command=self.open_selected_file)
        self.context_menu.add_command(label='打开文件位置', command=self.open_file_location)
        self.context_menu.add_command(label='复制文件', command=self.copy_file)
        
        # 绑定双击事件和右键菜单事件
        self.tree.bind('<Double-1>', self.open_file)
        self.tree.bind('<Button-3>', self.show_context_menu)
        
        # 用于存储搜索结果的队列和列表
        self.result_queue = queue.Queue()
        self.all_results = []
        self.searching = False
        self.stop_search_flag = False
    
    def browse_directory(self):
        directory = tk.filedialog.askdirectory()
        if directory:
            self.path_var.set(directory)
    
    def start_search(self):
        if self.searching:
            return
        
        self.stop_search_flag = False
        
        search_path = self.path_var.get()
        keyword = self.keyword_var.get()
        
        if not os.path.exists(search_path):
            messagebox.showerror('错误', '搜索路径不存在!')
            return
        
        if not keyword:
            messagebox.showerror('错误', '请输入搜索关键词!')
            return
        
        # 清空现有结果和存储
        for item in self.tree.get_children():
            self.tree.delete(item)
        self.all_results.clear()
        
        self.searching = True
        self.search_btn.configure(text='搜索中...', state='disabled')
        self.stop_btn.configure(state='normal')
        
        # 启动搜索线程
        search_thread = threading.Thread(target=self.search_files, args=(search_path, keyword))
        search_thread.daemon = True
        search_thread.start()
        
        # 启动更新UI的定时器
        self.root.after(100, self.update_results)
    
    def search_files(self, path, keyword):
        try:
            selected_type = self.type_var.get()
            file_extensions = self.file_types[selected_type]
            
            # 将关键词按空格、中英文标点符号分隔成列表
            # 支持空格、中英文逗号、分号、顿号、斜杠、竖线等常用分隔符
            separators = [',', '、', ',', ';', ';', '/', '\\', '|', '|']
            for sep in separators:
                keyword = keyword.replace(sep, ' ')
            keywords = [k.strip().lower() for k in keyword.split() if k.strip()]
            
            for root, dirs, files in os.walk(path):
                if self.stop_search_flag:
                    break
                for file in files:
                    if self.stop_search_flag:
                        break
                    # 过滤缓存文件和特定文件类型
                    file_lower = file.lower()
                    file_ext = os.path.splitext(file_lower)[1]
                    if any(pattern in file_lower for pattern in ['cache', 'temp', '.tmp']) or \
                       file_ext in ['.wps', '.lnk', '.et']:
                        continue
                    # 检查文件名是否包含任意一个关键词
                    if any(k in file_lower for k in keywords):
                        # 检查文件类型
                        if selected_type != '全部':
                            file_ext = os.path.splitext(file)[1].lower()
                            if file_ext not in file_extensions:
                                continue
                        
                        file_path = os.path.join(root, file)
                        try:
                            size = os.path.getsize(file_path)
                            modified = os.path.getmtime(file_path)
                            result = {
                                'name': file,
                                'path': root,
                                'size': self.format_size(size),
                                'modified': self.format_time(modified)
                            }
                            self.result_queue.put(result)
                            self.all_results.append(result)
                        except OSError:
                            continue
        finally:
            self.searching = False
            self.root.after(0, self.reset_search_ui)
    
    def update_results(self):
        while not self.result_queue.empty():
            result = self.result_queue.get()
            self.tree.insert('', 'end', values=(
                result['name'],
                result['path'],
                result['size'],
                result['modified']
            ))
        
        if self.searching:
            self.root.after(100, self.update_results)
        else:
            self.reset_search_ui()
    
    def reset_search_ui(self):
        self.search_btn.configure(text='搜索', state='normal')
        self.stop_btn.configure(state='disabled')
    
    def on_type_changed(self, event):
        selected_type = self.type_var.get()
        file_extensions = self.file_types[selected_type]
        
        # 清空当前显示的结果
        for item in self.tree.get_children(""):
            self.tree.delete(item)
        
        # 如果没有搜索结果,直接返回
        if not self.all_results:
            return
        
        # 重新显示符合条件的结果
        for result in self.all_results:
            file_name = result['name']
            file_ext = os.path.splitext(file_name)[1].lower()
            
            # 判断是否显示该文件
            if selected_type == "全部" or (isinstance(file_extensions, list) and file_ext in file_extensions):
                self.tree.insert('', 'end', values=(
                    result['name'],
                    result['path'],
                    result['size'],
                    result['modified']
                ))
    
    def stop_search(self):
        self.stop_search_flag = True
    
    def show_context_menu(self, event):
        item = self.tree.identify_row(event.y)
        if item:
            self.tree.selection_set(item)
            self.context_menu.post(event.x_root, event.y_root)
    
    def open_selected_file(self):
        self.open_file(None)
    
    def open_file_location(self):
        selected_item = self.tree.selection()
        if not selected_item:
            return
        
        values = self.tree.item(selected_item[0])['values']
        file_path = os.path.join(values[1], values[0])
        
        try:
            os.system(f'explorer /select,"{file_path}"')
        except OSError:
            messagebox.showerror('错误', '无法打开文件位置!')
    
    def format_size(self, size):
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024:
                return f'{size:.1f} {unit}'
            size /= 1024
        return f'{size:.1f} TB'
    
    def format_time(self, timestamp):
        from datetime import datetime
        return datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M')
    
    def open_file(self, event):
        selected_item = self.tree.selection()
        if not selected_item:
            return
        
        values = self.tree.item(selected_item[0])['values']
        file_path = os.path.join(values[1], values[0])
        
        try:
            os.startfile(file_path)
        except OSError:
            messagebox.showerror('错误', '无法打开文件!')

    
    def on_keyword_entry_focus_in(self, event):
        if self.keyword_entry.get() == '支持空格、逗号、分号等分隔符':
            self.keyword_entry.delete(0, tk.END)
            self.keyword_entry.config(foreground='black')
    
    def on_keyword_entry_focus_out(self, event):
        if not self.keyword_entry.get():
            self.keyword_entry.insert(0, '支持空格、逗号、分号等分隔符')
            self.keyword_entry.config(foreground='gray')

    
    def reset_search(self):
        # 清空搜索结果
        for item in self.tree.get_children():
            self.tree.delete(item)
        self.all_results.clear()
        
        # 重置搜索关键词
        self.keyword_entry.delete(0, tk.END)
        self.keyword_entry.insert(0, '支持空格、逗号、分号等分隔符')
        self.keyword_entry.config(foreground='gray')
        
        # 重置文件类型为全部
        self.type_var.set('全部')
    
    def copy_file(self):
        selected_item = self.tree.selection()
        if not selected_item:
            return
        
        values = self.tree.item(selected_item[0])['values']
        source_path = os.path.join(values[1], values[0])
        
        # 选择目标目录
        target_dir = filedialog.askdirectory(title='选择复制目标文件夹')
        if not target_dir:
            return
        
        try:
            import shutil
            target_path = os.path.join(target_dir, values[0])
            shutil.copy2(source_path, target_path)
            messagebox.showinfo('成功', '文件复制成功!')
        except Exception as e:
            messagebox.showerror('错误', f'复制失败:{str(e)}')

    def export_results(self):
        if not self.tree.get_children():
            messagebox.showwarning('警告', '没有可导出的搜索结果!')
            return
        
        file_path = filedialog.asksaveasfilename(
            defaultextension='.xlsx',
            filetypes=[('Excel 文件', '*.xlsx')],
            title='导出搜索结果'
        )
        
        if not file_path:
            return
        
        try:
            wb = Workbook()
            ws = wb.active
            
            # 写入表头
            headers = ['文件名', '路径', '大小', '修改时间']
            for col, header in enumerate(headers, 1):
                ws.cell(row=1, column=col, value=header)
            
            # 写入数据
            for row, item in enumerate(self.tree.get_children(), 2):
                values = self.tree.item(item)['values']
                for col, value in enumerate(values, 1):
                    ws.cell(row=row, column=col, value=value)
            
            wb.save(file_path)
            messagebox.showinfo('成功', '搜索结果已成功导出!')
        except Exception as e:
            messagebox.showerror('错误', f'导出失败:{str(e)}')


    
    def batch_copy_files(self):
        # 获取所有选中的项
        selected_items = self.tree.selection()
        if not selected_items:
            messagebox.showwarning('警告', '请选择要复制的文件!')
            return
        
        # 选择目标目录
        target_dir = filedialog.askdirectory(title='选择复制目标文件夹')
        if not target_dir:
            return
        
        try:
            import shutil
            success_count = 0
            failed_files = []
            
            for item in selected_items:
                values = self.tree.item(item)['values']
                source_path = os.path.join(values[1], values[0])
                target_path = os.path.join(target_dir, values[0])
                
                try:
                    shutil.copy2(source_path, target_path)
                    success_count += 1
                except Exception as e:
                    failed_files.append(f'{values[0]}: {str(e)}')
            
            # 显示复制结果
            if failed_files:
                error_msg = '\n'.join(failed_files)
                messagebox.showwarning('复制完成', 
                    f'成功复制 {success_count} 个文件\n'
                    f'失败 {len(failed_files)} 个文件:\n{error_msg}')
            else:
                messagebox.showinfo('成功', f'已成功复制 {success_count} 个文件!')
        except Exception as e:
            messagebox.showerror('错误', f'复制失败:{str(e)}')

if __name__ == '__main__':
    root = tk.Tk()
    app = FileSearchApp(root)
    root.mainloop()


依赖

PyInstaller==6.12.0
openpyxl==3.1.2


打包
[Python] 纯文本查看 复制代码
import PyInstaller.__main__
import os
import subprocess
import sys

def check_requirements():
    # 获取当前脚本所在目录
    current_dir = os.path.dirname(os.path.abspath(__file__))
    requirements_path = os.path.join(current_dir, 'requirements.txt')
    
    # 检查requirements.txt文件是否存在
    if not os.path.exists(requirements_path):
        print('Error: requirements.txt file not found')
        return False
    
    # 安装依赖
    try:
        subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', requirements_path])
        return True
    except subprocess.CalledProcessError as e:
        print(f'Error installing dependencies: {e}')
        return False

def build_exe():
    # 获取当前目录
    current_dir = os.path.dirname(os.path.abspath(__file__))
    
    # 设置图标文件路径(如果有的话)
    icon_path = os.path.join(current_dir, 'search_icon.ico')
    
    # PyInstaller参数
    # 设置主程序文件的绝对路径
    main_script = os.path.join(current_dir, 'file_search.py')
    
    params = [
        main_script,  # 主程序文件
        '--name=吾爱破解论坛本地全局搜索',  # 生成的exe名称
        '--noconsole',  # 不显示控制台窗口
        '--onefile',  # 打包成单个exe文件
        f'--icon={icon_path}',  # 设置图标
        '--clean',  # 清理临时文件
        '--noconfirm',  # 不确认覆盖
        '--distpath', os.path.join(current_dir, 'dist'),  # 输出目录
        '--workpath', os.path.join(current_dir, 'build'),  # 工作目录
        '--specpath', current_dir,  # spec文件目录
    ]
    
    # 执行打包
    PyInstaller.__main__.run(params)

if __name__ == '__main__':
    if check_requirements():
        build_exe()
    else:
        print('安装依赖时出现了错误. 检查 requirements.txt 然后重试.')


icon图标自己找喜欢的

已打包成品,按需自取,不喜勿喷,如有违规,请管理联系,自行删除,感谢。
https://wwwn.lanzoum.com/iQw2v2sbaqbe
密码:52pj

免费评分

参与人数 9吾爱币 +15 热心值 +9 收起 理由
szllw + 2 + 1 Everything 中有你需要的所有功能
zhulen + 1 热心回复!
jiangsg + 1 + 1 热心回复!
6khome + 1 + 1 谢谢@Thanks!
windyz + 1 + 1 用心讨论,共获提升!
caihuachaorou87 + 1 + 1 谢谢@Thanks!
schtg + 1 + 1 谢谢@Thanks!
pbgz + 1 + 1 谢谢@Thanks!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 薄了微凉 发表于 2025-4-3 09:02
tear2008 发表于 2025-4-3 07:52
电脑不是有搜索功能吗,区别在哪

电脑搜索需要一个一个搜,没试过联合搜索,
只是自己为了方便联合搜索,找到结果,通过类型去筛选,类型支持自己去添加需要的
当然网上有现成的其他搜索工具,自己写的这个肯定和人家的没法比,
这个只是为了方便自用,分享出来,按需自取
当前只是做了文件名的查询,内容 以及 连接ftp的没有做
为了方便保留原文件,复制出来新文件进行分享,修改
不与他人争长短,只为方便当下用

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
tear2008 + 1 + 1 谢谢@Thanks!

查看全部评分

locoman 发表于 2025-4-4 22:43
请问:您这个“ 支持关键词联合搜索(中英文 逗号,分号,空格等分隔符)”
是支持文件名称的关键词?还是文件内容的关键词?
boisbb 发表于 2025-4-3 07:36
tear2008 发表于 2025-4-3 07:52
电脑不是有搜索功能吗,区别在哪
老墙 发表于 2025-4-3 08:02
试试速度和准确度
ghostzl 发表于 2025-4-3 08:35
win自带的不好用,试试这个
sjxsyy2004 发表于 2025-4-3 10:37
下载了试试,谢谢楼主分享。
huailonglong521 发表于 2025-4-3 10:48
不错 不错。
zhuangaoni 发表于 2025-4-3 17:03
感谢发布原创作品,吾爱破解论坛因你更精彩!
tianyuan22 发表于 2025-4-3 17:58
这个比较简洁,不错 支持下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-4-17 09:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表