最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Python實(shí)現(xiàn)一個(gè)高效本地文件智能搜索工具

 更新時(shí)間:2025年12月26日 09:10:41   作者:ChenAI_TGF  
在日常工作中,我們經(jīng)常需要在本地磁盤中搜索特定文件,本文將基于Python開發(fā)一款輕量高效的文件智能搜索工具,文中的示例代碼講解詳細(xì),需要的可以了解下

前言

在日常工作中,我們經(jīng)常需要在本地磁盤中搜索特定文件——可能是根據(jù)文件名或者文件內(nèi)容查找文檔。Windows自帶的搜索功能往往響應(yīng)緩慢,而第三方工具又可能存在功能冗余或廣告干擾的問(wèn)題。為此,開發(fā)了一款輕量高效的文件智能搜索工具,基于Python實(shí)現(xiàn),支持多線程加速、文件類型篩選和關(guān)鍵詞高亮等功能,完全滿足日常文件檢索需求。

代碼倉(cāng)庫(kù)已經(jīng)上傳到github 可以通過(guò)鏈接直接下載:https://github.com/ChenAI-TGF/File_Search_Tool

原理簡(jiǎn)介

這款工具的核心設(shè)計(jì)思路是通過(guò)多進(jìn)程并行處理提升搜索效率,同時(shí)利用GUI界面簡(jiǎn)化操作流程,主要涉及以下技術(shù)點(diǎn):

  • 界面構(gòu)建:使用Tkinter庫(kù)實(shí)現(xiàn)圖形界面,包含路徑選擇、關(guān)鍵詞輸入、文件類型篩選、進(jìn)度展示和結(jié)果顯示等模塊,確保操作直觀簡(jiǎn)潔。
  • 多進(jìn)程搜索:通過(guò)multiprocessing庫(kù)實(shí)現(xiàn)并行搜索,充分利用CPU多核性能。主進(jìn)程負(fù)責(zé)界面交互,子進(jìn)程處理文件掃描和內(nèi)容匹配,避免單線程搜索導(dǎo)致的界面卡頓。
  • 進(jìn)程間通信:使用Manager創(chuàng)建跨進(jìn)程共享的隊(duì)列(Queue)和事件(Event),實(shí)現(xiàn)搜索進(jìn)度更新、結(jié)果傳遞和搜索終止控制。
  • 文件類型篩選:通過(guò)擴(kuò)展名匹配實(shí)現(xiàn)精準(zhǔn)的文件類型過(guò)濾,支持預(yù)設(shè)類別(如音頻、視頻、文檔等)和自定義擴(kuò)展名添加,僅搜索用戶指定類型的文件。
  • 關(guān)鍵詞匹配:使用正則表達(dá)式實(shí)現(xiàn)文件名和文件內(nèi)容的模糊匹配,支持大小寫不敏感搜索,并在結(jié)果中高亮顯示匹配內(nèi)容。

完整代碼

以下是工具的完整實(shí)現(xiàn)代碼,包含詳細(xì)注釋便于理解和二次開發(fā):

import os
import re
import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext, messagebox, simpledialog
import multiprocessing as mp
from multiprocessing import Pool, Manager
import queue
import threading
from functools import partial
import mimetypes

# 定義文件類型分類(可擴(kuò)展)
FILE_TYPE_CATEGORIES = {
    "音頻文件": ['.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma', '.m4a', '.ape', '.alac'],
    "視頻文件": ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.mpg', '.mpeg', '.rmvb', '.3gp'],
    "圖像文件": ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.svg', '.psd', '.ai'],
    "文檔文件": ['.doc', '.docx', '.pdf', '.txt', '.xls', '.xlsx', '.ppt', '.pptx', '.md', '.rtf'],
    "壓縮文件": ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'],
    "程序文件": ['.exe', '.dll', '.py', '.java', '.c', '.cpp', '.js', '.html', '.css']
}

class FileSearchApp:
    def __init__(self, root):
        self.root = root
        self.root.title("文件智能搜索工具")
        self.root.geometry("1200x700")
        self.root.minsize(1000, 600)
        
        # 設(shè)置中文字體
        self.style = ttk.Style()
        self.style.configure(".", font=("SimHei", 10))
        
        # 搜索參數(shù)
        self.search_path = tk.StringVar()
        self.keyword = tk.StringVar()
        self.search_type = tk.StringVar(value="name")  # name 或 content
        self.is_searching = False
        self.manager = Manager()  # 用于創(chuàng)建跨進(jìn)程共享對(duì)象
        self.stop_event = self.manager.Event()  # 跨進(jìn)程停止事件
        
        # 文件類型篩選狀態(tài)(只搜索選中的類型)
        self.category_vars = {}  # 存儲(chǔ)類別勾選狀態(tài)
        self.extension_vars = {}  # 存儲(chǔ)擴(kuò)展名勾選狀態(tài)
        self.included_extensions = set()  # 當(dāng)前選中的要包含的擴(kuò)展名
        self.other_files_frame = None  # "其他文件"類別的擴(kuò)展架子框架
        
        # 創(chuàng)建UI
        self.create_widgets()
        # 初始化文件類型篩選狀態(tài)(默認(rèn)不選中任何類型)
        self.init_file_type_filters()
        
        # 進(jìn)程和隊(duì)列
        self.progress_queue = None
        self.result_queue = None
        self.search_process = None
        
        # 搜索統(tǒng)計(jì)
        self.total_files = 0
        self.processed_files = 0
        self.matched_files = 0

    def create_widgets(self):
        # 主框架分割為左右兩部分
        main_paned = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
        main_paned.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 左側(cè):文件類型篩選面板
        filter_frame = ttk.LabelFrame(main_paned, text="文件類型篩選(只搜索選中類型)", padding="10")
        main_paned.add(filter_frame, weight=1)
        
        # 篩選面板滾動(dòng)區(qū)域
        self.filter_canvas = tk.Canvas(filter_frame)
        self.filter_scrollbar = ttk.Scrollbar(filter_frame, orient="vertical", command=self.filter_canvas.yview)
        self.filter_scrollable_frame = ttk.Frame(self.filter_canvas)
        
        self.filter_scrollable_frame.bind(
            "<Configure>",
            lambda e: self.filter_canvas.configure(scrollregion=self.filter_canvas.bbox("all"))
        )
        
        self.filter_canvas.create_window((0, 0), window=self.filter_scrollable_frame, anchor="nw")
        self.filter_canvas.configure(yscrollcommand=self.filter_scrollbar.set)
        
        self.filter_canvas.pack(side="left", fill="both", expand=True)
        self.filter_scrollbar.pack(side="right", fill="y")
        
        # 添加文件類型分類和擴(kuò)展名復(fù)選框
        for category, extensions in FILE_TYPE_CATEGORIES.items():
            # 類別總復(fù)選框
            cat_var = tk.BooleanVar()
            self.category_vars[category] = cat_var
            cat_check = ttk.Checkbutton(
                self.filter_scrollable_frame, 
                text=category, 
                variable=cat_var,
                command=partial(self.toggle_category, category)
            )
            cat_check.pack(anchor=tk.W, pady=5)
            
            # 該類別下的擴(kuò)展名復(fù)選框
            ext_frame = ttk.Frame(self.filter_scrollable_frame)
            ext_frame.pack(anchor=tk.W, padx=20)
            
            for ext in extensions:
                ext_var = tk.BooleanVar()
                self.extension_vars[ext] = ext_var
                ext_check = ttk.Checkbutton(
                    ext_frame, 
                    text=ext, 
                    variable=ext_var,
                    command=partial(self.update_category_state, category)
                )
                ext_check.pack(side=tk.LEFT, padx=5, pady=2)
        
        # 添加自定義擴(kuò)展名按鈕
        ttk.Button(
            filter_frame, 
            text="添加自定義擴(kuò)展名", 
            command=self.add_custom_extension
        ).pack(pady=10, fill=tk.X)
        
        # 右側(cè):主功能區(qū)
        right_frame = ttk.Frame(main_paned)
        main_paned.add(right_frame, weight=3)
        
        # 頂部框架 - 路徑選擇
        path_frame = ttk.Frame(right_frame, padding="10")
        path_frame.pack(fill=tk.X)
        
        ttk.Label(path_frame, text="搜索路徑:").pack(side=tk.LEFT, padx=5)
        ttk.Entry(path_frame, textvariable=self.search_path, width=50).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        ttk.Button(path_frame, text="瀏覽...", command=self.browse_path).pack(side=tk.LEFT, padx=5)
        
        # 中間框架 - 搜索設(shè)置
        search_frame = ttk.Frame(right_frame, padding="10")
        search_frame.pack(fill=tk.X)
        
        ttk.Label(search_frame, text="搜索關(guān)鍵詞:").pack(side=tk.LEFT, padx=5)
        ttk.Entry(search_frame, textvariable=self.keyword, width=30).pack(side=tk.LEFT, padx=5)
        
        ttk.Radiobutton(search_frame, text="按文件名", variable=self.search_type, value="name").pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(search_frame, text="按文件內(nèi)容", variable=self.search_type, value="content").pack(side=tk.LEFT, padx=5)
        
        ttk.Button(search_frame, text="開始搜索", command=self.start_search).pack(side=tk.LEFT, padx=5)
        ttk.Button(search_frame, text="停止搜索", command=self.stop_search).pack(side=tk.LEFT, padx=5)
        
        # 進(jìn)度框架
        progress_frame = ttk.Frame(right_frame, padding="10")
        progress_frame.pack(fill=tk.X)
        
        ttk.Label(progress_frame, text="總體進(jìn)度:").pack(side=tk.LEFT, padx=5)
        self.overall_progress = ttk.Progressbar(progress_frame, orient="horizontal", length=100, mode="determinate")
        self.overall_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 階段進(jìn)度框架
        stage_frame = ttk.Frame(right_frame, padding="10")
        stage_frame.pack(fill=tk.X)
        
        ttk.Label(stage_frame, text="當(dāng)前階段:").pack(side=tk.LEFT, padx=5)
        self.stage_label = ttk.Label(stage_frame, text="準(zhǔn)備就緒")
        self.stage_label.pack(side=tk.LEFT, padx=5)
        
        self.stage_progress = ttk.Progressbar(stage_frame, orient="horizontal", length=100, mode="determinate")
        self.stage_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 狀態(tài)框架
        status_frame = ttk.Frame(right_frame, padding="10")
        status_frame.pack(fill=tk.X)
        
        self.status_label = ttk.Label(status_frame, text="等待開始搜索...")
        self.status_label.pack(anchor=tk.W)
        
        # 結(jié)果框架
        result_frame = ttk.LabelFrame(right_frame, text="搜索結(jié)果", padding="10")
        result_frame.pack(fill=tk.BOTH, expand=True)
        
        self.result_display = scrolledtext.ScrolledText(result_frame, wrap=tk.WORD)
        self.result_display.pack(fill=tk.BOTH, expand=True, pady=5)
        # 配置不同內(nèi)容的樣式標(biāo)簽
        self.result_display.tag_configure("filename", foreground="blue", font=("SimHei", 10, "bold"))
        self.result_display.tag_configure("linenum", foreground="green", font=("SimHei", 10))
        self.result_display.tag_configure("match", background="yellow")
        self.result_display.tag_configure("separator", foreground="gray")
        
        # 統(tǒng)計(jì)信息框架
        stats_frame = ttk.Frame(right_frame, padding="10")
        stats_frame.pack(fill=tk.X)
        
        self.stats_label = ttk.Label(stats_frame, text="文件總數(shù): 0 | 已處理: 0 | 匹配: 0")
        self.stats_label.pack(anchor=tk.W)

    def init_file_type_filters(self):
        """初始化文件類型篩選狀態(tài)(默認(rèn)不選中任何類型)"""
        pass  # 保持默認(rèn)不選中

    def toggle_category(self, category, init=False):
        """切換整個(gè)類別的選中狀態(tài),同步子項(xiàng)"""
        target_state = self.category_vars[category].get()
        for ext in FILE_TYPE_CATEGORIES[category]:
            self.extension_vars[ext].set(target_state)
        if not init:
            self.update_included_extensions()

    def update_category_state(self, category):
        """根據(jù)子項(xiàng)狀態(tài)更新類別復(fù)選框狀態(tài)"""
        extensions = FILE_TYPE_CATEGORIES[category]
        checked_count = sum(1 for ext in extensions if self.extension_vars[ext].get())
        
        # 全選則勾選類別,否則不勾選
        self.category_vars[category].set(checked_count == len(extensions))
        self.update_included_extensions()

    def update_included_extensions(self):
        """更新當(dāng)前選中的要包含的擴(kuò)展名集合"""
        self.included_extensions = {
            ext for ext, var in self.extension_vars.items() if var.get()
        }

    def add_custom_extension(self):
        """添加自定義擴(kuò)展名"""
        ext = simpledialog.askstring("添加自定義擴(kuò)展名", "請(qǐng)輸入擴(kuò)展名(帶點(diǎn),如 .log):")
        if not ext:
            return
            
        # 格式化擴(kuò)展名
        if not ext.startswith('.'):
            ext = '.' + ext
        ext = ext.lower()
        
        # 檢查是否已存在
        if ext in self.extension_vars:
            messagebox.showinfo("提示", f"擴(kuò)展名 {ext} 已存在")
            return
            
        # 添加到"其他文件"類別(如果不存在則創(chuàng)建)
        if "其他文件" not in FILE_TYPE_CATEGORIES:
            FILE_TYPE_CATEGORIES["其他文件"] = []
            # 創(chuàng)建類別復(fù)選框
            cat_var = tk.BooleanVar()
            self.category_vars["其他文件"] = cat_var
            cat_check = ttk.Checkbutton(
                self.filter_scrollable_frame,
                text="其他文件", 
                variable=cat_var,
                command=partial(self.toggle_category, "其他文件")
            )
            cat_check.pack(anchor=tk.W, pady=5)
            
            # 創(chuàng)建擴(kuò)展架子框架
            self.other_files_frame = ttk.Frame(self.filter_scrollable_frame)
            self.other_files_frame.pack(anchor=tk.W, padx=20)
        
        # 添加到類別列表
        FILE_TYPE_CATEGORIES["其他文件"].append(ext)
        
        # 創(chuàng)建復(fù)選框
        ext_var = tk.BooleanVar()
        self.extension_vars[ext] = ext_var
        ext_check = ttk.Checkbutton(
            self.other_files_frame,
            text=ext, 
            variable=ext_var,
            command=partial(self.update_category_state, "其他文件")
        )
        ext_check.pack(side=tk.LEFT, padx=5, pady=2)
        
        messagebox.showinfo("成功", f"已添加自定義擴(kuò)展名 {ext}")

    def browse_path(self):
        path = filedialog.askdirectory()
        if path:
            self.search_path.set(path)

    def start_search(self):
        if self.is_searching:
            messagebox.showinfo("提示", "正在搜索中,請(qǐng)先停止當(dāng)前搜索")
            return
            
        path = self.search_path.get()
        keyword = self.keyword.get()
        
        if not path:
            messagebox.showerror("錯(cuò)誤", "請(qǐng)選擇搜索路徑")
            return
            
        if not keyword:
            messagebox.showerror("錯(cuò)誤", "請(qǐng)輸入搜索關(guān)鍵詞")
            return
            
        if not os.path.exists(path):
            messagebox.showerror("錯(cuò)誤", "所選路徑不存在")
            return
        
        # 檢查是否選擇了文件類型
        self.update_included_extensions()
        if not self.included_extensions:
            messagebox.showerror("錯(cuò)誤", "請(qǐng)至少選擇一種文件類型")
            return
            
        # 初始化搜索狀態(tài)
        self.is_searching = True
        self.stop_event.clear()  # 重置停止事件
        self.result_display.delete(1.0, tk.END)
        self.total_files = 0
        self.processed_files = 0
        self.matched_files = 0
        self.update_stats()
        
        # 創(chuàng)建隊(duì)列
        self.progress_queue = self.manager.Queue()
        self.result_queue = self.manager.Queue()
        
        # 啟動(dòng)搜索進(jìn)程
        self.search_process = threading.Thread(
            target=self.perform_search,
            args=(path, keyword, self.search_type.get())
        )
        self.search_process.daemon = True
        self.search_process.start()
        
        # 啟動(dòng)進(jìn)度和結(jié)果處理線程
        self.root.after(100, self.process_queue_updates)

    def stop_search(self):
        if self.is_searching and self.search_process:
            self.stop_event.set()
            self.status_label.config(text="正在停止搜索...")

    def perform_search(self, root_path, keyword, search_type):
        try:
            # 階段1: 掃描所有文件并過(guò)濾(只保留選中類型)
            self.progress_queue.put(("stage", "掃描文件并過(guò)濾(只保留選中類型)", 0))
            
            # 獲取所有文件列表
            all_files = []
            for dirpath, _, filenames in os.walk(root_path):
                if self.stop_event.is_set():
                    self.progress_queue.put(("done", "搜索已停止"))
                    return
                    
                for filename in filenames:
                    file_path = os.path.join(dirpath, filename)
                    # 檢查文件擴(kuò)展名是否在選中的類型中
                    ext = os.path.splitext(filename)[1].lower()
                    if ext in self.included_extensions:  # 只搜索選中類型
                        all_files.append(file_path)
                
                # 更新進(jìn)度
                total_scanned = len(all_files)
                progress = min(100, int((total_scanned / (total_scanned + 1)) * 100))  # 避免除以0
                self.progress_queue.put(("stage", "掃描文件并過(guò)濾(只保留選中類型)", progress))
            
            self.total_files = len(all_files)
            self.progress_queue.put(("total_files", self.total_files))
            self.progress_queue.put(("stage", "掃描文件并過(guò)濾完成", 100))
            
            if self.total_files == 0:
                self.progress_queue.put(("done", "未找到符合條件的文件類型"))
                return
                
            # 階段2: 搜索文件
            self.progress_queue.put(("stage", f"正在{('搜索文件名' if search_type == 'name' else '搜索文件內(nèi)容')}", 0))
            
            # 使用多進(jìn)程搜索
            num_processes = min(mp.cpu_count(), self.total_files)
            chunk_size = max(1, self.total_files // num_processes)
            
            with Pool(processes=num_processes) as pool:
                # 部分應(yīng)用函數(shù)參數(shù)
                if search_type == 'name':
                    search_func = partial(
                        search_filename, 
                        keyword=keyword, 
                        stop_event=self.stop_event,
                        progress_queue=self.progress_queue
                    )
                else:
                    search_func = partial(
                        search_file_content, 
                        keyword=keyword, 
                        stop_event=self.stop_event,
                        progress_queue=self.progress_queue
                    )
                
                # 異步處理文件列表
                results = []
                for i in range(0, self.total_files, chunk_size):
                    chunk = all_files[i:i+chunk_size]
                    results.append(pool.apply_async(search_func, args=(chunk,)))
                
                # 收集結(jié)果
                for result in results:
                    matched_in_chunk = result.get()
                    for file_path, matches in matched_in_chunk:
                        self.result_queue.put((file_path, matches))
                    
                    if self.stop_event.is_set():
                        pool.terminate()
                        self.progress_queue.put(("done", "搜索已停止"))
                        return
            
            self.progress_queue.put(("done", "搜索完成"))
            
        except Exception as e:
            self.progress_queue.put(("error", str(e)))

    def process_queue_updates(self):
        if not self.is_searching:
            return
            
        # 處理進(jìn)度更新
        try:
            while not self.progress_queue.empty():
                item = self.progress_queue.get_nowait()
                if item[0] == "stage":
                    stage_name, progress = item[1], item[2]
                    self.stage_label.config(text=stage_name)
                    self.stage_progress["value"] = progress
                elif item[0] == "progress":
                    self.processed_files = item[1]
                    overall_progress = (self.processed_files / self.total_files) * 100 if self.total_files > 0 else 0
                    self.overall_progress["value"] = overall_progress
                    self.status_label.config(text=f"正在處理: {item[2]}")
                    self.update_stats()
                elif item[0] == "total_files":
                    self.total_files = item[1]
                    self.update_stats()
                elif item[0] == "done":
                    self.status_label.config(text=item[1])
                    self.is_searching = False
                elif item[0] == "error":
                    messagebox.showerror("錯(cuò)誤", f"搜索過(guò)程中發(fā)生錯(cuò)誤: {item[1]}")
                    self.is_searching = False
        
        except queue.Empty:
            pass
        
        # 處理結(jié)果更新
        try:
            while not self.result_queue.empty():
                item = self.result_queue.get_nowait()
                file_path, matches = item
                self.matched_files += 1
                self.display_result(file_path, matches)
                self.update_stats()
        except queue.Empty:
            pass
        
        # 繼續(xù)檢查隊(duì)列或結(jié)束
        if self.is_searching:
            self.root.after(100, self.process_queue_updates)
        else:
            self.overall_progress["value"] = 100
            self.stage_progress["value"] = 100

    def display_result(self, file_path, matches):
        # 插入分割線
        self.result_display.insert(tk.END, "----------------------------\n", "separator")
        
        # 顯示文件名(藍(lán)色加粗)
        self.result_display.insert(tk.END, f"文件路徑: {file_path}\n", "filename")
        
        # 如果有匹配內(nèi)容,顯示行數(shù)和匹配片段
        if matches and self.search_type.get() == "content":
            self.result_display.insert(tk.END, "  匹配內(nèi)容:\n")
            for line_num, line_content in matches[:5]:  # 只顯示前5個(gè)匹配
                # 顯示行數(shù)(綠色)
                self.result_display.insert(tk.END, f"    第{line_num}行: ", "linenum")
                start_pos = self.result_display.index(tk.END)
                self.result_display.insert(tk.END, line_content + "\n")
                end_pos = self.result_display.index(tk.END)
                
                # 標(biāo)記匹配的關(guān)鍵詞(黃色高亮)
                start = start_pos
                keyword = self.keyword.get()
                while True:
                    start = self.result_display.search(keyword, start, end_pos, nocase=True)
                    if not start:
                        break
                    line, col = map(int, start.split('.'))
                    end = f"{line}.{col + len(keyword)}"
                    self.result_display.tag_add("match", start, end)
                    start = end
        
        self.result_display.see(tk.END)

    def update_stats(self):
        self.stats_label.config(
            text=f"文件總數(shù): {self.total_files} | 已處理: {self.processed_files} | 匹配: {self.matched_files}"
        )

# 多進(jìn)程輔助函數(shù) - 搜索文件名
def search_filename(files, keyword, stop_event, progress_queue):
    matched = []
    pattern = re.compile(re.escape(keyword), re.IGNORECASE)
    
    for i, file_path in enumerate(files):
        if stop_event.is_set():
            return []
            
        filename = os.path.basename(file_path)
        if pattern.search(filename):
            matched.append((file_path, []))
            
        # 更新進(jìn)度
        if i % 10 == 0 or i == len(files) - 1:
            progress_queue.put(("progress", i + 1, file_path))
    
    return matched

# 多進(jìn)程輔助函數(shù) - 搜索文件內(nèi)容
def search_file_content(files, keyword, stop_event, progress_queue):
    matched = []
    pattern = re.compile(re.escape(keyword), re.IGNORECASE)
    
    for i, file_path in enumerate(files):
        if stop_event.is_set():
            return []
            
        try:
            # 嘗試確定文件類型,跳過(guò)二進(jìn)制文件
            mime_type, _ = mimetypes.guess_type(file_path)
            if mime_type and mime_type.startswith(('image/', 'audio/', 'video/')):
                continue
                
            # 嘗試以文本方式打開文件
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                matches_in_file = []
                for line_num, line in enumerate(f, 1):
                    if pattern.search(line):
                        # 截取匹配行的上下文
                        start = max(0, line.find(keyword) - 30)
                        end = min(len(line), line.find(keyword) + len(keyword) + 30)
                        snippet = line[start:end].replace('\n', ' ').replace('\r', '')
                        matches_in_file.append((line_num, snippet))
                        
                        # 限制每個(gè)文件最多記錄10個(gè)匹配
                        if len(matches_in_file) >= 10:
                            break
                
                if matches_in_file:
                    matched.append((file_path, matches_in_file))
                    
        except (IOError, UnicodeDecodeError):
            # 無(wú)法讀取的文件跳過(guò)
            pass
            
        # 更新進(jìn)度
        if i % 10 == 0 or i == len(files) - 1:
            progress_queue.put(("progress", i + 1, file_path))
    
    return matched

if __name__ == "__main__":
    # 在Windows上運(yùn)行多進(jìn)程需要保護(hù)主模塊
    if os.name == 'nt':
        mp.set_start_method('spawn')
    
    root = tk.Tk()
    app = FileSearchApp(root)
    root.mainloop()

效果演示

工具的界面布局清晰,主要分為以下幾個(gè)區(qū)域:

1.左側(cè):文件類型篩選區(qū)

包含預(yù)設(shè)的6大類別(音頻、視頻、圖像、文檔、壓縮、程序文件),每個(gè)類別下有對(duì)應(yīng)的擴(kuò)展名復(fù)選框。用戶可通過(guò)勾選指定需要搜索的文件類型,也可點(diǎn)擊"添加自定義擴(kuò)展名"按鈕補(bǔ)充特殊格式(如.log.json等)。

2.右側(cè)上半部分:搜索控制區(qū)

  • 路徑選擇:支持手動(dòng)輸入或通過(guò)"瀏覽"按鈕選擇搜索根目錄
  • 關(guān)鍵詞輸入:支持任意字符串,區(qū)分"按文件名"和"按文件內(nèi)容"兩種搜索模式
  • 操作按鈕:"開始搜索"啟動(dòng)任務(wù),"停止搜索"可隨時(shí)終止正在進(jìn)行的搜索
  • 進(jìn)度展示:包含總體進(jìn)度條(已處理文件占比)和階段進(jìn)度條(當(dāng)前執(zhí)行步驟),實(shí)時(shí)顯示處理狀態(tài)

3.右側(cè)下半部分:結(jié)果展示區(qū)

以結(jié)構(gòu)化方式展示匹配結(jié)果:

  • 文件名以藍(lán)色加粗顯示,清晰區(qū)分不同文件
  • 內(nèi)容搜索時(shí),綠色標(biāo)注匹配行號(hào),關(guān)鍵詞以黃色高亮顯示上下文片段
  • 底部統(tǒng)計(jì)信息實(shí)時(shí)更新文件總數(shù)、已處理數(shù)和匹配數(shù)

4.操作流程示例

  • 在左側(cè)勾選"文檔文件"類別(自動(dòng)選中.doc、.pdf、.txt等擴(kuò)展名)
  • 選擇搜索路徑(如D:\工作文檔
  • 輸入關(guān)鍵詞"項(xiàng)目計(jì)劃",選擇"按內(nèi)容搜索"
  • 點(diǎn)擊"開始搜索",工具先掃描篩選符合條件的文件,再并行搜索內(nèi)容
  • 結(jié)果區(qū)域?qū)崟r(shí)顯示包含"項(xiàng)目計(jì)劃"的文檔路徑及匹配位置

到此這篇關(guān)于基于Python實(shí)現(xiàn)一個(gè)高效本地文件智能搜索工具的文章就介紹到這了,更多相關(guān)Python本地文件智能搜索內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python 如何上傳包到pypi

    python 如何上傳包到pypi

    這篇文章主要介紹了python 如何上傳包到pypi,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-12-12
  • 通過(guò)mod_python配置運(yùn)行在Apache上的Django框架

    通過(guò)mod_python配置運(yùn)行在Apache上的Django框架

    這篇文章主要介紹了通過(guò)mod_python配置運(yùn)行在Apache上的Django框架,Django是最具人氣的Python web開發(fā)框架,需要的朋友可以參考下
    2015-07-07
  • Python進(jìn)階之高級(jí)用法詳細(xì)總結(jié)

    Python進(jìn)階之高級(jí)用法詳細(xì)總結(jié)

    今天帶各位小伙伴學(xué)習(xí)一下Python高級(jí)語(yǔ)法,主要有Lambda表達(dá)式,map函數(shù),filter函數(shù),reduce函數(shù),三大推導(dǎo)式等,文中有非常詳細(xì)的介紹,需要的朋友可以參考下
    2021-05-05
  • 使用Python實(shí)現(xiàn)自動(dòng)查找并高亮Word文檔中的文本

    使用Python實(shí)現(xiàn)自動(dòng)查找并高亮Word文檔中的文本

    在處理 Word 文檔時(shí),很多用戶經(jīng)常需要查找并高亮特定文本,本文將演示如何使用Python高亮首個(gè)匹配的文本和高亮文檔中所有匹配的文本,感興趣的小伙伴可以了解下
    2026-01-01
  • Pandas中iloc[]和loc[]的實(shí)現(xiàn)示例

    Pandas中iloc[]和loc[]的實(shí)現(xiàn)示例

    Pandas中的iloc[]和loc[]是數(shù)據(jù)索引的核心方法,主要區(qū)別在于索引依據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2026-04-04
  • 使用Python處理PDF文件的實(shí)踐分享

    使用Python處理PDF文件的實(shí)踐分享

    在現(xiàn)代數(shù)字化時(shí)代,PDF(Portable?Document?Format)文件已經(jīng)成為廣泛使用的電子文檔格式,這篇文章主要為分享了Python處理PDF文件的簡(jiǎn)介與實(shí)踐,需要的可以參考下
    2023-06-06
  • Python中使用實(shí)現(xiàn)輸出哈沙德數(shù)的多種方法小結(jié)

    Python中使用實(shí)現(xiàn)輸出哈沙德數(shù)的多種方法小結(jié)

    哈沙德數(shù)(Harshad?Number),又稱Niven數(shù),是指一個(gè)自然數(shù),它可以被它的各位數(shù)字之和整除,本文將探討如何使用多種不同的方法來(lái)判斷一個(gè)數(shù)字是否是哈沙德數(shù),感興趣的可以了解下
    2024-01-01
  • python hash每次調(diào)用結(jié)果不同的原因

    python hash每次調(diào)用結(jié)果不同的原因

    這篇文章主要介紹了python hash每次調(diào)用結(jié)果不同的原因,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Python數(shù)據(jù)分析之Numpy庫(kù)的使用詳解

    Python數(shù)據(jù)分析之Numpy庫(kù)的使用詳解

    NumPy(Numerical Python)是Python的一種開源的數(shù)值計(jì)算擴(kuò)展。這種工具可用來(lái)存儲(chǔ)和處理大型矩陣,比Python自身的嵌套列表結(jié)構(gòu)要高效的多(該結(jié)構(gòu)也可以用來(lái)表示矩陣(matrix)),支持大量的維度數(shù)組與矩陣運(yùn)算,此外也針對(duì)數(shù)組運(yùn)算提供大量的數(shù)學(xué)函數(shù)庫(kù)
    2021-11-11
  • Python Flask框架使用介紹

    Python Flask框架使用介紹

    今天來(lái)給大家說(shuō)一個(gè)Python的輕量級(jí)web開發(fā)框架——Flask,為什么要推薦它呢?當(dāng)然是因?yàn)樗鼔蜉p量級(jí)了,開發(fā)迅速是它的特點(diǎn),當(dāng)然它也有缺點(diǎn),不過(guò)這里不說(shuō),因?yàn)榧扔盟终f(shuō)它差感覺不好
    2022-08-08

最新評(píng)論

眉山市| 兴安县| 托克托县| 长葛市| 靖安县| 房产| 昆明市| 太仓市| 陇川县| 大田县| 玉溪市| 闻喜县| 望江县| 黄平县| 景谷| 泗洪县| 南宁市| 华坪县| 吕梁市| 宜昌市| 和平县| 会理县| 江口县| 黎川县| 浏阳市| 翁源县| 眉山市| 铁力市| 德安县| 平度市| 湾仔区| 桓仁| 无极县| 斗六市| 伊宁市| 吴桥县| 高阳县| 巨鹿县| 孟州市| 六安市| 侯马市|