吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1238|回复: 35
收起左侧

[原创工具] 文本快速搜索工具-py代码

  [复制链接]
己中求 发表于 2025-3-21 18:19
之前发了一个文本快速搜索工具,想不到这么久还有人私聊我,看来有文本搜索需求的人不少,
最近使用py重构了一下文本快速搜索工具,速度没慢多少,就降低了一半,我感觉速度还可以接受。
2025年3月21日18时14分50秒.jpg

分享给大家希望,能帮助有需要的人。
下面直接发py代码,没python环境的划到最后,下载打包好的
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
import sys
import os
import time
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
    QLabel, QLineEdit, QPushButton, QTreeWidget, QTreeWidgetItem,
    QListWidget, QTextEdit, QScrollArea, QFileDialog, QMessageBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QMimeData, QSize
from PyQt6.QtGui import QDragEnterEvent, QDropEvent
 
class DraggableLineEdit(QLineEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
 
    def dragEnterEvent(self, event: QDragEnterEvent):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
 
    def dropEvent(self, event: QDropEvent):
        urls = event.mimeData().urls()
        if urls:
            path = urls[0].toLocalFile()
            if os.path.isdir(path) or os.path.isfile(path):
                self.setText(path)
 
class SearchWorker(QThread):
    update_file = pyqtSignal(dict)
    finished = pyqtSignal()
     
    def __init__(self, folder, extensions, keyword):
        super().__init__()
        self.folder = folder
        self.extensions = extensions
        self.keyword = keyword
        self.running = True
 
    def run(self):
        for root, _, files in os.walk(self.folder):
            if not self.running: break
            for file in files:
                if any(file.endswith(ext) for ext in self.extensions):
                    path = os.path.join(root, file)
                    if self.file_contains_keyword(path, self.keyword):
                        size = os.path.getsize(path)
                        self.update_file.emit({
                            "name": file,
                            "size": self.format_size(size),
                            "path": path
                        })
        self.finished.emit()
 
    def file_contains_keyword(self, path, keyword):
        for encoding in ['utf-8', 'gbk', 'latin-1']:
            try:
                with open(path, 'r', encoding=encoding) as f:
                    return any(keyword in line for line in f)
            except (UnicodeDecodeError, Exception):
                continue
        return False
 
    def format_size(self, size):
        if size < 1024:
            return f"{size} B"
        elif size < 1024 * 1024:
            return f"{size/1024:.1f} KB"
        else:
            return f"{size/(1024 * 1024):.1f} MB"
 
class FileReader(QThread):
    update_line = pyqtSignal(str)
    finished = pyqtSignal()
     
    def __init__(self, path, keyword):
        super().__init__()
        self.path = path
        self.keyword = keyword
        self.results = []
 
    def run(self):
        self.results = []
        for encoding in ['utf-8', 'gbk', 'latin-1']:
            try:
                with open(self.path, 'r', encoding=encoding) as f:
                    for i, line in enumerate(f, 1):
                        if self.keyword in line:
                            text = f"Line {i}: {line.strip()[:50]}"
                            self.update_line.emit(text)
                            self.results.append(line.strip())
                break
            except (UnicodeDecodeError, Exception):
                continue
        self.finished.emit()
 
class AllFilesReader(QThread):
    update_line = pyqtSignal(str)
    finished = pyqtSignal()
     
    def __init__(self, paths, keyword):
        super().__init__()
        self.paths = paths
        self.keyword = keyword
 
    def run(self):
        for path in self.paths:
            if not os.path.isfile(path):
                continue
            reader = FileReader(path, self.keyword)
            reader.update_line.connect(self.update_line.emit)
            reader.start()
            reader.wait()
        self.finished.emit()
 
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.current_matches = []
        self.search_thread = None
        self.file_reader = None
        self.start_time = 0
        self.init_ui()
 
    def init_ui(self):
        self.setWindowTitle("PyQt6文件搜索工具")
        self.setGeometry(100, 100, 1200, 700)
 
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        main_layout = QVBoxLayout(main_widget)
 
        # 顶部控制面板
        top_panel = QWidget()
        top_layout = QGridLayout(top_panel)
         
        self.folder_input = DraggableLineEdit()
        self.ext_input = QLineEdit(".txt")
        self.keyword_input = QLineEdit()
        self.btn_search = QPushButton("开始搜索")
        self.btn_search.clicked.connect(self.start_search)
 
        top_layout.addWidget(QLabel("目标文件夹:"), 0, 0)
        top_layout.addWidget(self.folder_input, 0, 1)
        top_layout.addWidget(self.create_browse_btn(), 0, 2)
        top_layout.addWidget(QLabel("文件后缀:"), 1, 0)
        top_layout.addWidget(self.ext_input, 1, 1)
        top_layout.addWidget(QLabel("搜索内容:"), 2, 0)
        top_layout.addWidget(self.keyword_input, 2, 1)
        top_layout.addWidget(self.btn_search, 0, 3, 3, 1)
 
        # 统计信息
        stats_panel = QWidget()
        stats_layout = QHBoxLayout(stats_panel)
        self.file_count = QLabel("文件总数: 0")
        self.line_count = QLabel("匹配行数: 0")
        self.time_label = QLabel("耗时: 0.00秒")
        stats_layout.addWidget(self.file_count)
        stats_layout.addWidget(self.line_count)
        stats_layout.addWidget(self.time_label)
 
        # 主内容区域
        content_panel = QWidget()
        content_layout = QHBoxLayout(content_panel)
 
        # 左侧结果树
        self.tree = QTreeWidget()
        self.tree.setHeaderLabels(["文件名", "大小", "路径"])
        self.tree.setColumnWidth(0, 250)
        self.tree.setColumnWidth(1, 100)
        self.tree.doubleClicked.connect(self.on_tree_double_click)
        tree_scroll = QScrollArea()
        tree_scroll.setWidgetResizable(True)
        tree_scroll.setWidget(self.tree)
 
        # 右侧面板
        right_panel = QWidget()
        right_layout = QVBoxLayout(right_panel)
 
        # 按钮面板
        btn_panel = QWidget()
        btn_layout = QHBoxLayout(btn_panel)
        self.btn_search_all = QPushButton("搜索所有文件")
        self.btn_export_matches = QPushButton("导出结果")
        self.btn_export_tree = QPushButton("导出树信息")
        self.btn_import_tree = QPushButton("导入树信息")
        btn_layout.addWidget(self.btn_search_all)
        btn_layout.addWidget(self.btn_export_matches)
        btn_layout.addWidget(self.btn_export_tree)
        btn_layout.addWidget(self.btn_import_tree)
 
        # 单文件搜索
        single_panel = QWidget()
        single_layout = QHBoxLayout(single_panel)
        self.single_input = DraggableLineEdit()
        btn_single = QPushButton("搜索")
        btn_single.clicked.connect(self.single_file_search)
        single_layout.addWidget(QLabel("单文件搜索:"))
        single_layout.addWidget(self.single_input)
        single_layout.addWidget(btn_single)
 
        # 匹配列表
        self.match_list = QListWidget()
        self.match_list.doubleClicked.connect(self.on_list_double_click)
        list_scroll = QScrollArea()
        list_scroll.setWidgetResizable(True)
        list_scroll.setWidget(self.match_list)
 
        # 详情文本框
        self.detail_text = QTextEdit()
        self.detail_text.setReadOnly(True)
 
        right_layout.addWidget(single_panel)
        right_layout.addWidget(btn_panel)
        right_layout.addWidget(list_scroll)
        right_layout.addWidget(self.detail_text)
 
        content_layout.addWidget(tree_scroll)
        content_layout.addWidget(right_panel)
 
        main_layout.addWidget(top_panel)
        main_layout.addWidget(stats_panel)
        main_layout.addWidget(content_panel)
 
        # 连接新按钮信号
        self.btn_search_all.clicked.connect(self.search_all_files)
        self.btn_export_matches.clicked.connect(self.export_match_list)
        self.btn_export_tree.clicked.connect(self.export_tree_info)
        self.btn_import_tree.clicked.connect(self.import_tree_info)
 
    def create_browse_btn(self):
        btn = QPushButton("浏览")
        btn.clicked.connect(self.browse_folder)
        btn.setFixedSize(QSize(80, 30))
        return btn
 
    def browse_folder(self):
        path = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if path:
            self.folder_input.setText(path)
 
    def start_search(self):
        if self.search_thread and self.search_thread.isRunning():
            return
 
        folder = self.folder_input.text()
        exts = self.ext_input.text().strip().split(";")
        keyword = self.keyword_input.text().strip()
 
        if not all([folder, exts, keyword]):
            QMessageBox.critical(self, "错误", "请填写所有搜索条件")
            return
 
        self.tree.clear()
        self.match_list.clear()
        self.current_matches = []
        self.update_counts()
        self.start_time = time.time()
 
        self.search_thread = SearchWorker(folder, exts, keyword)
        self.search_thread.update_file.connect(self.add_file_result)
        self.search_thread.finished.connect(self.on_search_finished)
        self.search_thread.start()
        self.btn_search.setEnabled(False)
 
    def add_file_result(self, data):
        item = QTreeWidgetItem()
        item.setText(0, data["name"])
        item.setText(1, data["size"])
        item.setText(2, data["path"])
        self.tree.addTopLevelItem(item)
        self.file_count.setText(f"文件总数: {self.tree.topLevelItemCount()}")
 
    def on_search_finished(self):
        self.btn_search.setEnabled(True)
        elapsed = time.time() - self.start_time
        self.time_label.setText(f"耗时: {elapsed:.2f}秒")
 
    def single_file_search(self):
        path = self.single_input.text()
        keyword = self.keyword_input.text().strip()
 
        if not os.path.isfile(path):
            QMessageBox.critical(self, "错误", "无效的文件路径")
            return
 
        self.match_list.clear()
        self.current_matches = []
        self.file_reader = FileReader(path, keyword)
        self.file_reader.update_line.connect(self.match_list.addItem)
        self.file_reader.finished.connect(lambda: (
            self.line_count.setText(f"匹配行数: {self.match_list.count()}"),
            self.current_matches.extend(self.file_reader.results)
        ))
        self.file_reader.start()
 
    def on_tree_double_click(self):
        item = self.tree.currentItem()
        if not item: return
         
        path = item.text(2)
        keyword = self.keyword_input.text().strip()
        self.match_list.clear()
        self.current_matches = []
         
        self.file_reader = FileReader(path, keyword)
        self.file_reader.update_line.connect(self.match_list.addItem)
        self.file_reader.finished.connect(lambda: (
            self.line_count.setText(f"匹配行数: {self.match_list.count()}"),
            self.current_matches.extend(self.file_reader.results)
        ))
        self.file_reader.start()
 
    def on_list_double_click(self):
        index = self.match_list.currentRow()
        if 0 <= index < len(self.current_matches):
            self.detail_text.setPlainText(self.current_matches[index])
 
    def search_all_files(self):
        paths = []
        root = self.tree.invisibleRootItem()
        for i in range(root.childCount()):
            item = root.child(i)
            paths.append(item.text(2))
 
        keyword = self.keyword_input.text().strip()
        if not keyword:
            QMessageBox.critical(self, "错误", "请输入搜索关键字")
            return
 
        self.match_list.clear()
        self.current_matches = []
        self.all_files_reader = AllFilesReader(paths, keyword)
        self.all_files_reader.update_line.connect(self.match_list.addItem)
        self.all_files_reader.finished.connect(lambda: (
            self.line_count.setText(f"匹配行数: {self.match_list.count()}"),
            self.current_matches.extend(self.file_reader.results) if self.file_reader else None
        ))
        self.all_files_reader.start()
 
    def export_match_list(self):
        keyword = self.keyword_input.text().strip() or "search"
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        filename = f"{keyword}_{timestamp}.txt"
        desktop = f"D:/桌面/"
        path = os.path.join(desktop, filename)
 
        with open(path, 'w', encoding='utf-8') as f:
            for i in range(self.match_list.count()):
                f.write(self.match_list.item(i).text() + "\n")
 
        QMessageBox.information(self, "导出完成", f"文件已保存到:{path}")
 
    def export_tree_info(self):
        items = []
        root = self.tree.invisibleRootItem()
        for i in range(root.childCount()):
            item = root.child(i)
            items.append("\t".join([
                item.text(0),
                item.text(1),
                item.text(2)
            ]))
 
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        filename = f"tree_export_{timestamp}.txt"
        desktop = f"D:/桌面/"
        path = os.path.join(desktop, filename)
 
        with open(path, 'w', encoding='utf-8') as f:
            f.write("\n".join(items))
 
        QMessageBox.information(self, "导出完成", f"树结构已保存到:{path}")
 
    def import_tree_info(self):
        path, _ = QFileDialog.getOpenFileName(self, "选择导入文件", "", "文本文件 (*.txt)")
        if not path:
            return
 
        self.tree.clear()
        with open(path, 'r', encoding='utf-8') as f:
            for line in f:
                parts = line.strip().split('\t')
                if len(parts) != 3:
                    continue
                item = QTreeWidgetItem()
                item.setText(0, parts[0])
                item.setText(1, parts[1])
                item.setText(2, parts[2])
                self.tree.addTopLevelItem(item)
        self.file_count.setText(f"文件总数: {self.tree.topLevelItemCount()}")
 
    def update_counts(self):
        self.file_count.setText(f"文件总数: {self.tree.topLevelItemCount()}")
        self.line_count.setText(f"匹配行数: {self.match_list.count()}")
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())




蓝奏打包好的链接:https://wwfh.lanzout.com/islwx2r8v6ch

免费评分

参与人数 8吾爱币 +13 热心值 +6 收起 理由
1506249352 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
aqtd2 + 1 热心回复!
aria1983 + 1 + 1 用心讨论,共获提升!
kedvfu + 1 谢谢@Thanks!
wwr21 + 1 + 1 谢谢@Thanks!
会飞的花 + 1 + 1 谢谢@Thanks!
lwGoodChinese + 1 谢谢@Thanks!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

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

bacon159 发表于 2025-3-21 18:55
谢谢楼主
dongrgg 发表于 2025-3-21 19:04
sjc140400 发表于 2025-3-21 19:38
softwkl 发表于 2025-3-21 20:59
谢谢分享
xianshiqi 发表于 2025-3-21 21:17
楼主辛苦!之前的就挺不错,试试新版
xiaohan2025 发表于 2025-3-21 21:53
谢谢分享
ACGZOOM 发表于 2025-3-21 22:00
这个牛了,可以搜索文档内容
MumuLC 发表于 2025-3-21 22:35
谢谢分享!
飘浮 发表于 2025-3-22 09:10
下载测试下。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2025-3-28 05:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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