探径者 目录名/文件结构递归生成工具

查看 12|回复 1
作者:wuyi001   

[color=]目录/文件递归检索工具功能简介

[color=]本软件是一个功能强大的目录和文件检索工具,具有直观的图形界面,能够帮助用户快速分析文件系统结构。主要功能如下:

[color=]核心功能

[color=]1. 目录结构检索

  • [color=]递归扫描

    [color=]:深度遍历指定目录及其所有子目录

  • [color=]多种检索模式

    [color=]:


  • [color=]仅文件夹模式:只显示目录结构

  • [color=]仅文件模式:只显示文件列表

  • [color=]文件+文件夹模式:完整显示目录树结构(默认模式)

    [color=]2. 智能过滤系统

  • [color=]文件后缀过滤

    [color=]:支持多后缀过滤(如:.txt; .py; .jpg)

  • [color=]屏蔽词管理

    [color=]:


  • [color=]支持通配符(如
    [color=]

    [color=].tmp; backup_

    [color=])

  • [color=]可创建和管理多个屏蔽配置

  • [color=]支持导入/导出配置



  • image.png (233.61 KB, 下载次数: 0)
    下载附件
    2025-6-3 08:46 上传


    [color=]3. 结果输出

  • [color=]树形结构展示

    [color=]:直观显示目录层级关系

  • [color=]可视化标识

    [color=]:

  • [color=]统计信息

    [color=]:自动生成项目数量统计

  • [color=]结果导出

    [color=]:一键导出为文本文件



  • image.png (420.6 KB, 下载次数: 0)
    下载附件
    2025-6-3 08:46 上传


    [color=]特色功能

    [color=]4. 用户友好界面

  • [color=]直观操作

    [color=]:清晰的按钮布局和分组

  • [color=]深色主题

    [color=]:减轻视觉疲劳

  • [color=]实时状态提示

    [color=]:显示当前操作状态

  • [color=]智能路径建议

    [color=]:自动生成默认输出路径

    [color=]5. 配置管理

  • [color=]配置文件存储

    [color=]:配置文件保存在程序同目录

  • [color=]多配置支持

    [color=]:可创建和管理多个屏蔽配置

  • [color=]配置导出

    [color=]:支持将配置导出为JSON文件

    [color=]6. 高效性能

  • [color=]快速扫描

    [color=]:优化递归算法提高效率

  • [color=]错误处理

    [color=]:自动跳过无权限访问的目录

  • [color=]排序功能

    [color=]:文件和文件夹按名称排序

    [color=]使用场景

  • [color=]项目结构分析

    [color=]:快速查看项目目录结构

  • [color=]文件系统清理

    [color=]:识别特定类型的文件(如临时文件)

  • [color=]文档编制

    [color=]:生成项目目录树文档

  • [color=]资产盘点

    [color=]:统计特定类型的文件数量

  • [color=]系统维护

    [color=]:查找分散的配置文件或日志文件

    [color=]本工具特别适合开发人员、系统管理员和数据分析师使用,能够显著提高文件系统分析的效率。

    [color=]源代码

    import os
    import sys
    import re
    import json
    import fnmatch
    from PyQt5.QtWidgets import (
        QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
        QPushButton, QRadioButton, QButtonGroup, QGroupBox, QFileDialog, QTextEdit,
        QComboBox, QMessageBox, QCheckBox, QListWidget, QListWidgetItem, QInputDialog
    )
    from PyQt5.QtCore import Qt
    from PyQt5.QtGui import QFont, QPalette, QColor
    # 获取脚本所在目录
    if getattr(sys, 'frozen', False):
        # 如果是打包后的可执行文件
        APP_DIR = os.path.dirname(sys.executable)
    else:
        # 如果是脚本文件
        APP_DIR = os.path.dirname(os.path.abspath(__file__))
    # 修改配置文件路径为脚本所在目录
    CONFIG_FILE = os.path.join(APP_DIR, "config.json")
    class FileSearchApp(QMainWindow):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("目录/文件递归检索工具")
            self.setGeometry(300, 300, 800, 650)
            # 初始化变量
            self.ignore_configs = []
            self.current_ignore_config = {"name": "默认配置", "patterns": []}
            self.load_config()
            # 创建UI
            self.init_ui()
    class FileSearchApp(QMainWindow):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("目录/文件递归检索工具 V1.0 by:Sunf10wer")
            self.setGeometry(300, 300, 800, 650)
            # 初始化变量
            self.ignore_configs = []
            self.current_ignore_config = {"name": "默认配置", "patterns": []}
            self.load_config()
            # 创建UI
            self.init_ui()
        def init_ui(self):
            # 主布局
            main_widget = QWidget()
            main_layout = QVBoxLayout()
            main_widget.setLayout(main_layout)
            self.setCentralWidget(main_widget)
            # 设置标题样式
            title_label = QLabel("目录/文件递归检索工具")
            title_font = QFont("Arial", 16, QFont.Bold)
            title_label.setFont(title_font)
            title_label.setAlignment(Qt.AlignCenter)
            title_label.setStyleSheet("color: #FFFFFF; padding: 10px;")
            main_layout.addWidget(title_label)
            # 目录选择
            dir_layout = QHBoxLayout()
            dir_label = QLabel("目标目录:")
            self.dir_entry = QLineEdit()
            self.dir_entry.setPlaceholderText("请选择或输入要检索的目录...")
            browse_button = QPushButton("浏览...")
            browse_button.clicked.connect(self.browse_directory)
            dir_layout.addWidget(dir_label)
            dir_layout.addWidget(self.dir_entry, 4)
            dir_layout.addWidget(browse_button, 1)
            main_layout.addLayout(dir_layout)
            # 输出文件选择
            output_layout = QHBoxLayout()
            output_label = QLabel("输出文件:")
            self.output_entry = QLineEdit()
            self.output_entry.setPlaceholderText("输出文件名...")
            output_browse_button = QPushButton("浏览...")
            output_browse_button.clicked.connect(self.browse_output_file)
            output_layout.addWidget(output_label)
            output_layout.addWidget(self.output_entry, 4)
            output_layout.addWidget(output_browse_button, 1)
            main_layout.addLayout(output_layout)
            # 检索类型选择
            search_type_group = QGroupBox("检索类型")
            search_layout = QHBoxLayout()
            self.folder_radio = QRadioButton("仅文件夹")
            self.file_radio = QRadioButton("仅文件")
            self.both_radio = QRadioButton("文件和文件夹")
            self.both_radio.setChecked(True)
            self.search_type_group = QButtonGroup()
            self.search_type_group.addButton(self.folder_radio)
            self.search_type_group.addButton(self.file_radio)
            self.search_type_group.addButton(self.both_radio)
            # 文件后缀过滤
            suffix_layout = QHBoxLayout()
            suffix_label = QLabel("文件后缀(用分号分隔):")
            self.suffix_entry = QLineEdit()
            self.suffix_entry.setPlaceholderText("例如: .txt; .py; .jpg")
            suffix_layout.addWidget(suffix_label)
            suffix_layout.addWidget(self.suffix_entry)
            search_layout.addWidget(self.folder_radio)
            search_layout.addWidget(self.file_radio)
            search_layout.addWidget(self.both_radio)
            search_layout.addStretch()
            search_type_group.setLayout(search_layout)
            main_layout.addWidget(search_type_group)
            main_layout.addLayout(suffix_layout)
            # 屏蔽词管理
            ignore_group = QGroupBox("屏蔽词管理")
            ignore_layout = QVBoxLayout()
            # 屏蔽词配置选择
            config_layout = QHBoxLayout()
            config_label = QLabel("当前配置:")
            self.config_combo = QComboBox()
            self.config_combo.setMinimumWidth(150)
            self.config_combo.currentIndexChanged.connect(self.config_selected)
            new_config_btn = QPushButton("新建配置")
            new_config_btn.clicked.connect(self.create_new_config)
            config_layout.addWidget(config_label)
            config_layout.addWidget(self.config_combo, 1)
            config_layout.addWidget(new_config_btn)
            # 屏蔽词列表
            ignore_list_layout = QVBoxLayout()
            list_label = QLabel("屏蔽词列表(支持通配符,如 *.tmp; backup_*)")
            self.ignore_list = QListWidget()
            self.ignore_list.setAlternatingRowColors(True)
            add_btn = QPushButton("添加屏蔽词")
            add_btn.clicked.connect(self.add_ignore_pattern)
            remove_btn = QPushButton("移除选中")
            remove_btn.clicked.connect(self.remove_selected_pattern)
            list_btn_layout = QHBoxLayout()
            list_btn_layout.addWidget(add_btn)
            list_btn_layout.addWidget(remove_btn)
            ignore_list_layout.addWidget(list_label)
            ignore_list_layout.addWidget(self.ignore_list)
            ignore_list_layout.addLayout(list_btn_layout)
            ignore_layout.addLayout(config_layout)
            ignore_layout.addLayout(ignore_list_layout)
            ignore_group.setLayout(ignore_layout)
            main_layout.addWidget(ignore_group)
            # 操作按钮
            button_layout = QHBoxLayout()
            self.search_btn = QPushButton("开始检索")
            self.search_btn.setStyleSheet(
                "background-color: #3498db; color: white; font-weight: bold; padding: 8px;"
            )
            self.search_btn.clicked.connect(self.start_search)
            export_btn = QPushButton("导出配置")
            export_btn.clicked.connect(self.export_config)
            button_layout.addStretch()
            button_layout.addWidget(self.search_btn)
            button_layout.addWidget(export_btn)
            button_layout.addStretch()
            main_layout.addLayout(button_layout)
            # 状态栏
            self.status_bar = self.statusBar()
            self.status_label = QLabel("就绪")
            self.status_bar.addWidget(self.status_label)
            # 更新UI
            self.update_config_combo()
            self.update_ignore_list()
            # 连接信号
            self.dir_entry.textChanged.connect(self.update_output_filename)
        def load_config(self):
            """从配置文件加载屏蔽词配置"""
            if os.path.exists(CONFIG_FILE):
                try:
                    with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
                        self.ignore_configs = json.load(f)
                    # 确保至少有一个默认配置
                    if not any(cfg['name'] == '默认配置' for cfg in self.ignore_configs):
                        self.ignore_configs.insert(0, {"name": "默认配置", "patterns": []})
                except:
                    self.ignore_configs = [{"name": "默认配置", "patterns": []}]
            else:
                self.ignore_configs = [{"name": "默认配置", "patterns": []}]
            self.current_ignore_config = self.ignore_configs[0]
        def save_config(self):
            """保存屏蔽词配置到文件"""
            try:
                with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                    json.dump(self.ignore_configs, f, ensure_ascii=False, indent=2)
                return True
            except Exception as e:
                QMessageBox.critical(self, "保存错误", f"保存配置时出错: {str(e)}")
                return False
        def update_config_combo(self):
            """更新配置下拉框"""
            self.config_combo.clear()
            for config in self.ignore_configs:
                self.config_combo.addItem(config['name'])
            # 选择当前配置
            current_index = next(
                (i for i, config in enumerate(self.ignore_configs)
                 if config['name'] == self.current_ignore_config['name']),
                0
            )
            self.config_combo.setCurrentIndex(current_index)
        def update_ignore_list(self):
            """更新屏蔽词列表"""
            self.ignore_list.clear()
            for pattern in self.current_ignore_config['patterns']:
                self.ignore_list.addItem(pattern)
        def config_selected(self, index):
            """配置选择改变事件"""
            if 0  0 else ""
                        # 添加文件夹/文件标识
                        if item['type'] == 'folder':
                            line = f"{indent}{prefix} {item['name']}/"
                            total_folders += 1
                        else:
                            line = f"{indent}{prefix} {item['name']}"
                            total_files += 1
                        f.write(line + "\n")
                        total_items += 1
                    # 添加统计信息
                    f.write("\n" + "=" * 70 + "\n\n")
                    f.write(f"统计信息:\n")
                    f.write(f"总项目数: {total_items}\n")
                    f.write(f"文件夹数: {total_folders}\n")
                    f.write(f"文件数: {total_files}\n")
                self.status_label.setText(f"检索完成!找到 {total_items} 个项目,结果已保存到: {output_file}")
                QMessageBox.information(self, "完成",
                    f"检索完成!\n"
                    f"总项目数: {total_items}\n"
                    f"文件夹数: {total_folders}\n"
                    f"文件数: {total_files}\n"
                    f"结果已保存到:\n{output_file}"
                )
            except Exception as e:
                self.status_label.setText("检索出错")
                QMessageBox.critical(self, "错误", f"检索过程中出错: {str(e)}")
        def recursive_traverse(self, root_dir, current_dir, results, depth,
                               search_folders, search_files, search_both,
                               file_extensions, ignore_patterns):
            """递归遍历目录,保持实际目录结构"""
            try:
                # 获取当前目录下的条目
                entries = os.listdir(current_dir)
            except Exception as e:
                # 跳过无权访问的目录
                return
            # 排序条目
            entries.sort(key=lambda s: s.lower())
            # 获取当前目录相对于根目录的相对路径
            rel_dir = os.path.relpath(current_dir, root_dir)
            # 如果是根目录,添加根目录项
            if current_dir == root_dir:
                results.append({
                    'name': os.path.basename(root_dir) or os.path.splitdrive(root_dir)[0],
                    'path': root_dir,
                    'depth': depth,
                    'type': 'folder'
                })
            # 处理文件夹
            folders = [e for e in entries if os.path.isdir(os.path.join(current_dir, e))]
            for folder in folders:
                folder_path = os.path.join(current_dir, folder)
                rel_path = os.path.relpath(folder_path, root_dir)
                # 检查是否在屏蔽列表中
                if self.is_ignored(rel_path, ignore_patterns):
                    continue
                # 添加到结果(如果需要检索文件夹)
                if search_folders or search_both:
                    results.append({
                        'name': folder,
                        'path': folder_path,
                        'depth': depth + 1,
                        'type': 'folder'
                    })
                # 递归处理子目录
                self.recursive_traverse(
                    root_dir,
                    folder_path,
                    results,
                    depth + 1,
                    search_folders,
                    search_files,
                    search_both,
                    file_extensions,
                    ignore_patterns
                )
            # 处理文件
            files = [e for e in entries if os.path.isfile(os.path.join(current_dir, e))]
            for file in files:
                file_path = os.path.join(current_dir, file)
                rel_path = os.path.relpath(file_path, root_dir)
                # 检查是否在屏蔽列表中
                if self.is_ignored(rel_path, ignore_patterns):
                    continue
                # 检查文件后缀
                if (search_files or search_both) and file_extensions:
                    ext = os.path.splitext(file)[1].lower()
                    if ext not in file_extensions:
                        continue
                # 添加到结果
                if search_files or search_both:
                    results.append({
                        'name': file,
                        'path': file_path,
                        'depth': depth + 1,
                        'type': 'file'
                    })
        def is_ignored(self, path, patterns):
            """检查路径是否与任何屏蔽模式匹配"""
            for pattern in patterns:
                if fnmatch.fnmatch(path, pattern):
                    return True
                if pattern in path:
                    return True
            return False
    if __name__ == "__main__":
        app = QApplication([])
        app.setStyle("Fusion")
        # 设置应用样式
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(53, 53, 53))
        palette.setColor(QPalette.WindowText, Qt.white)
        palette.setColor(QPalette.Base, QColor(35, 35, 35))
        palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
        palette.setColor(QPalette.ToolTipBase, Qt.white)
        palette.setColor(QPalette.ToolTipText, Qt.white)
        palette.setColor(QPalette.Text, Qt.white)
        palette.setColor(QPalette.Button, QColor(53, 53, 53))
        palette.setColor(QPalette.ButtonText, Qt.white)
        palette.setColor(QPalette.BrightText, Qt.red)
        palette.setColor(QPalette.Highlight, QColor(142, 45, 197).lighter())
        palette.setColor(QPalette.HighlightedText, Qt.black)
        app.setPalette(palette)
        window = FileSearchApp()
        window.show()
        app.exec_()
    # 文件递归检索工具依赖库
    PyQt5==5.15.9
    pip install PyQt5
    pyinstaller --onefile -w so.py
    已打包版本,运行不了请自行打包
    https://wwky.lanzoue.com/in2AB2xk9v2d

    文件, 目录

  • Mainos   

    tree /F
    您需要登录后才可以回帖 登录 | 立即注册