Files
tree-generator/Releases/v1.0.0/source/t023-architecture-design.md
2026-05-16 17:34:32 +08:00

446 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 目录树生成脚本 — 技术方案设计Windows 平台)
> 任务 ID: T023 | 项目 ID: PROJ-20260509011
> 功能清单: F013-F0208 个功能,全部审批通过)
> 运行平台: Windows
> 设计日期: 2026-05-16
> 设计者: 脚本架构师
---
## 1. 技术选型评估
### 1.1 功能级可行性分析BAT vs Python
| 功能编号 | 功能名称 | BAT 可行性 | Python 可行性 | 关键问题 |
|---------|---------|-----------|--------------|---------|
| F013 | 接收路径输入 | ✅ 完全可行 | ✅ 完全可行 | BAT: `%~1` 即可Python: `argparse` |
| F014 | 加载忽略配置 | ⚠️ 勉强可行 | ✅ 完全可行 | BAT 读取配置文件需逐行 `for /f`,无结构化解析能力 |
| F015 | 递归遍历目录 | ⚠️ 勉强可行 | ✅ 完全可行 | BAT `for /r` 可递归但无法灵活控制跳过逻辑 |
| F016 | 生成目录树(├── 字符) | ❌ **不可行** | ✅ 完全可行 | Windows CMD 默认代码页 936 (GBK) 无法正确显示 `├` `─` 等 Unicode 制表符;需 `chcp 65001` 且仍有渲染问题。BAT 字符串拼接缩进极其困难 |
| F017 | 生成文件树 | ⚠️ 勉强可行 | ✅ 完全可行 | BAT `dir /s/b` 可列出文件,但格式化输出困难 |
| F018 | 终端输出 | ⚠️ 有条件可行 | ✅ 完全可行 | BAT 需处理 `chcp 65001` 编码切换,输出重定向时易乱码 |
| F019 | Markdown 保存 | ⚠️ 勉强可行 | ✅ 完全可行 | BAT 可 `echo > file.md`,但 Markdown 结构化内容拼接繁琐 |
| F020 | 统计信息(目录数/文件数/总大小) | ❌ **困难** | ✅ 完全可行 | BAT 无原生文件大小累加能力,`%%~zI``for` 循环中可用但累加大文件时易溢出BAT 整数仅支持 32 位) |
### 1.2 BAT 核心缺陷总结
1. **Unicode 制表符渲染**F016 要求输出 `├──` `└──` `│` 等字符Windows CMD 默认代码页下这些字符会显示为乱码。虽然 `chcp 65001` 可以切换 UTF-8但在 Windows 10 之前的系统上存在严重兼容性问题,且输出重定向到文件时编码转换不可靠。
2. **字符串处理**BAT 的字符串拼接、缩进管理极其笨拙,无法优雅实现树形缩进逻辑。
3. **大文件统计**BAT 的整数运算限制在 32 位有符号范围(约 ±21 亿),总大小超过 2GB 时会溢出。
4. **错误处理**BAT 缺乏结构化异常处理机制try/catch错误恢复困难。
5. **配置解析**BAT 无法优雅解析结构化配置文件JSON/INI只能逐行文本处理。
### 1.3 评估结论
**BAT 无法胜任 F016目录树 Unicode 渲染)和 F020大文件统计其余功能也均存在明显缺陷。**
---
## 2. 技术选型结论
### 最终选择Python 3.8+(标准库,无第三方依赖)
**理由:**
| 维度 | 说明 |
|-----|------|
| 功能覆盖 | 8 个功能全部可完美实现,无妥协 |
| Unicode 支持 | Python 原生 UTF-8 支持,`├──` 等字符渲染无问题 |
| 标准库 | `pathlib``os``argparse``datetime` 覆盖所有需求 |
| 文件大小 | Python 整数自动扩展,无溢出问题 |
| 跨版本兼容 | Python 3.8+ 覆盖 Windows 7 SP1 及以上所有版本 |
| 可维护性 | 代码结构清晰,模块化设计,易于扩展 |
| 部署 | 单文件 `.py`,用户只需安装 PythonWindows 10/11 可通过 Microsoft Store 一键安装) |
---
## 3. 项目结构
```
tree_generator/
├── tree_gen.py # 主程序(单文件,包含所有模块)
├── .treeignore # 忽略配置文件(可选,放在目标目录下)
├── tree_output.md # 默认输出文件(运行后生成)
└── README.md # 使用文档(由 Web 文档生成 Agent 创建)
```
**设计原则:**
- 主程序 `tree_gen.py` 为单文件,不拆分为多模块,便于分发和使用
- 忽略配置文件 `.treeignore` 放在目标目录下,遵循 `.gitignore` 惯例
- 输出文件默认在当前工作目录生成
---
## 4. 模块说明表
| 模块名 | 负责功能 | 输入 | 输出 | 依赖 |
|-------|---------|------|------|------|
| `ArgParser` | F013 路径输入 | 命令行参数 `sys.argv` | 解析后的配置对象(目标路径、输出路径、深度限制等) | `argparse` 标准库 |
| `IgnoreLoader` | F014 忽略配置 | 配置文件路径(`.treeignore` | 忽略目录名称集合 `set[str]` | `pathlib` 标准库 |
| `DirectoryScanner` | F015 递归遍历 | 目标路径 + 忽略集合 | 目录树结构(嵌套字典) | `pathlib``os` 标准库 |
| `TreeFormatter` | F016 目录树 + F017 文件树 | 目录树结构 | 格式化字符串(含 `├──` 缩进) | 无额外依赖 |
| `TerminalOutput` | F018 终端输出 | 格式化字符串 | 终端显示stdout | `sys` 标准库(编码设置) |
| `MarkdownWriter` | F019 Markdown 保存 | 格式化字符串 + 输出路径 | `.md` 文件 | `pathlib` 标准库 |
| `StatisticsCollector` | F020 统计信息 | 目录树结构 | 统计信息字典(目录数、文件数、总大小) | `os` 标准库 |
---
## 5. 技术选型结论总结
```
┌─────────────────────────────────────────────────────┐
│ 最终技术选型Python 3.8+ 标准库 │
│ │
│ 核心文件tree_gen.py单文件约 300-400 行) │
│ 配置文件:.treeignore可选
│ 输出文件tree_output.md默认
│ │
│ 选择理由: │
│ 1. BAT 无法正确处理 Unicode 制表符F016
│ 2. BAT 整数溢出问题F020 大文件统计) │
│ 3. Python 标准库完全覆盖所有 8 个功能 │
│ 4. 单文件部署,零第三方依赖 │
└─────────────────────────────────────────────────────┘
```
---
## 6. 错误处理策略
### 6.1 异常分类与处理
| 异常类型 | 触发条件 | 处理策略 | 用户提示 |
|---------|---------|---------|---------|
| `PathNotFoundError` | 目标路径不存在 | 捕获 `FileNotFoundError`,退出并提示 | `错误: 路径 "xxx" 不存在,请检查输入` |
| `PermissionError` | 无权限访问目录 | 跳过该目录,记录警告,继续遍历 | `警告: 无权限访问 "xxx",已跳过` |
| `SymlinkLoopError` | 符号链接循环 | 使用 `pathlib.Path.resolve()` 检测,跳过已访问路径 | `警告: 检测到符号链接循环,已跳过` |
| `EncodingError` | 文件名含特殊字符 | 使用 `errors='replace'` 容错 | 静默替换,不中断 |
| `OutputWriteError` | 无法写入输出文件 | 捕获 `IOError`/`PermissionError`,回退到仅终端输出 | `警告: 无法写入文件,仅显示到终端` |
| `InvalidConfigError` | 忽略配置文件格式错误 | 使用默认忽略列表,记录警告 | `警告: 配置文件格式错误,使用默认配置` |
### 6.2 退出码规范
| 退出码 | 含义 |
|-------|------|
| 0 | 成功完成 |
| 1 | 参数错误(路径不存在、格式错误) |
| 2 | 运行时错误(写入失败等) |
| 3 | 中断Ctrl+C |
---
## 7. 接口定义
### 7.1 数据流图
```
┌──────────┐ ┌──────────────┐ ┌─────────────────┐
│ 命令行参数 │────▶│ ArgParser │────▶│ Config 对象 │
│ sys.argv │ │ (F013) │ │ {path, output, │
└──────────┘ └──────────────┘ │ ignore, depth} │
└────────┬────────┘
┌───────────────────────────┼───────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│IgnoreLoader │ │Directory │ │Statistics │
│(F014) │ │Scanner │ │Collector │
│ │ │(F015) │ │(F020) │
│.treeignore │ │ │ │ │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
▼ ▼ │
ignore_set tree_dict │
(set[str]) (嵌套字典) │
│ │
▼ │
┌──────────────────┐ │
│ TreeFormatter │◀────────────────────┘
│ (F016/F017) │
│ │
│ tree_str │
│ file_list_str │
└────────┬────────┘
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Terminal │ │ Markdown │ │ 统计信息 │
│ Output │ │ Writer │ │ 输出 │
│ (F018) │ │ (F019) │ │ │
│ │ │ │ │ │
│ stdout │ │ tree_output │ │ 目录/文件/ │
│ │ │ .md │ │ 总大小 │
└──────────────┘ └──────────────┘ └──────────────┘
```
### 7.2 核心数据结构
```python
# Config 对象ArgParser 输出)
Config = {
"target_path": Path, # 目标目录路径
"output_path": Path, # Markdown 输出路径(默认 tree_output.md
"ignore_dirs": set[str], # 忽略目录名称集合
"max_depth": int | None, # 最大递归深度None = 无限制)
"files_only": bool, # 仅显示文件模式
"dirs_only": bool, # 仅显示目录模式
}
# 目录树结构DirectoryScanner 输出)
TreeDict = {
"name": str, # 目录/文件名
"path": Path, # 完整路径
"is_dir": bool, # 是否为目录
"children": list[TreeDict], # 子节点列表(目录时有效)
"size": int, # 文件大小(文件时有效)
}
# 统计信息StatisticsCollector 输出)
Statistics = {
"dir_count": int, # 目录数量
"file_count": int, # 文件数量
"total_size": int, # 总大小(字节)
"total_size_human": str, # 人类可读大小(如 "1.23 GB"
}
```
### 7.3 模块间接口
| 调用方 | 被调用方 | 接口方法 | 参数 | 返回值 |
|-------|---------|---------|------|--------|
| `main()` | `ArgParser` | `parse_args()` | `sys.argv[1:]` | `Config` |
| `main()` | `IgnoreLoader` | `load_ignores(config)` | `Config` | `set[str]` |
| `main()` | `DirectoryScanner` | `scan(path, ignore_set, max_depth)` | `Path, set[str], int\|None` | `TreeDict` |
| `main()` | `TreeFormatter` | `format_tree(tree, style)` | `TreeDict, str` | `str` |
| `main()` | `TreeFormatter` | `format_files(tree)` | `TreeDict` | `str` |
| `main()` | `TerminalOutput` | `output(text)` | `str` | `None` |
| `main()` | `MarkdownWriter` | `write(text, path)` | `str, Path` | `None` |
| `main()` | `StatisticsCollector` | `collect(tree)` | `TreeDict` | `Statistics` |
---
## 8. 忽略配置方案F014
### 8.1 配置文件格式
文件名:`.treeignore`(放在目标目录下)
```
# 忽略配置示例
# 每行一个目录名,支持 # 注释
.git
.gitignore
node_modules
__pycache__
*.pyc
.DS_Store
Thumbs.db
venv
.env
.idea
.vscode
dist
build
*.egg-info
```
### 8.2 内置默认忽略列表
`.treeignore` 不存在时,使用以下默认列表:
```python
DEFAULT_IGNORE = {
".git", ".svn", ".hg", # 版本控制
"node_modules", "bower_components", # Node.js
"__pycache__", "*.pyc", ".pytest_cache", # Python
".idea", ".vscode", # IDE
"dist", "build", "target", # 构建产物
".DS_Store", "Thumbs.db", # 系统文件
"venv", ".venv", "env", # 虚拟环境
}
```
### 8.3 匹配规则
- 目录名精确匹配不区分大小写Windows 特性)
- 支持 `*` 通配符(如 `*.pyc`
- 忽略配置仅作用于目录级别,不递归检查文件内容
---
## 9. 树形输出格式规范F016/F017
### 9.1 目录树格式
```
项目根目录/
├── src/
│ ├── main.py
│ ├── utils/
│ │ ├── helper.py
│ │ └── config.py
│ └── models/
│ └── user.py
├── tests/
│ ├── test_main.py
│ └── test_utils.py
├── config.json
└── README.md
```
**规则:**
- 目录名后加 `/` 后缀
- 分支符:`├── `(有后续兄弟节点)/ `└── `(最后一个节点)
- 缩进线:`│ `(有后续兄弟节点)/ ` `(无后续兄弟节点)
- 缩进单位4 个字符(`│` + 3 空格 或 4 空格)
### 9.2 文件树格式
```
文件列表:
C:\project\src\main.py
C:\project\src\utils\helper.py
C:\project\src\utils\config.py
C:\project\src\models\user.py
C:\project\tests\test_main.py
C:\project\tests\test_utils.py
C:\project\config.json
C:\project\README.md
```
**规则:**
- 每个文件一行,带完整绝对路径
- 使用 Windows 风格路径分隔符 `\`
- 按字母顺序排序
### 9.3 统计信息格式
```
统计信息:
目录数: 5
文件数: 8
总大小: 24.5 KB (25,088 字节)
```
---
## 10. Markdown 保存方案F019
### 10.1 输出文件格式
```markdown
# 目录树 — 项目根目录
> 生成时间: 2026-05-16 16:00:00
> 目标路径: C:\project
> 扫描深度: 无限制
## 目录结构
```
项目根目录/
├── src/
│ ├── main.py
│ └── utils/
│ └── helper.py
├── config.json
└── README.md
```
## 文件列表
| # | 文件路径 |
|---|---------|
| 1 | `C:\project\src\main.py` |
| 2 | `C:\project\src\utils\helper.py` |
| 3 | `C:\project\config.json` |
| 4 | `C:\project\README.md` |
## 统计信息
- **目录数:** 3
- **文件数:** 4
- **总大小:** 1.2 KB (1,234 字节)
```
### 10.2 保存策略
- 默认文件名:`tree_output.md`(当前工作目录)
- 可通过 `-o` / `--output` 参数指定自定义路径
- 文件已存在时覆盖写入(不追加)
- 编码UTF-8 with BOMWindows 记事本兼容)
---
## 11. 命令行接口设计
```
usage: tree_gen.py [-h] [-o OUTPUT] [-d DEPTH] [-f] [-D] [-i IGNORE_FILE] [path]
目录树生成脚本 - Windows 平台
positional arguments:
path 目标目录路径(默认: 当前目录)
options:
-h, --help 显示帮助信息
-o OUTPUT, --output OUTPUT
Markdown 输出文件路径(默认: tree_output.md
-d DEPTH, --depth DEPTH
最大递归深度(默认: 无限制)
-f, --files-only 仅显示文件树
-D, --dirs-only 仅显示目录树
-i IGNORE_FILE, --ignore IGNORE_FILE
忽略配置文件路径(默认: 目标目录下的 .treeignore
```
### 使用示例
```bash
# 扫描当前目录
python tree_gen.py
# 扫描指定目录
python tree_gen.py C:\Users\test\project
# 指定输出文件和深度
python tree_gen.py C:\project -o output.md -d 3
# 仅显示文件
python tree_gen.py C:\project -f
# 自定义忽略配置
python tree_gen.py C:\project -i my_ignore.txt
```
---
## 12. 编码规范
| 项目 | 规范 |
|-----|------|
| 文件编码 | UTF-8Python 源文件) |
| 输出编码 | UTF-8 with BOMMarkdown 文件) |
| 终端编码 | UTF-8通过 `sys.stdout.reconfigure(encoding='utf-8')` 设置) |
| 行尾符 | LFPython 标准) |
| 缩进 | 4 空格 |
| Python 版本 | 3.8+ |
---
## 13. 后续任务
| 任务 | 负责 Agent | 状态 |
|-----|-----------|------|
| T021: Python 代码实现 | BAT 编码 Agent实际应为 Python 编码 Agent | 待激活 |
| T022: 功能测试验证 | 测试验证 Agent | 待激活 |
| T024: 使用文档编写 | Web 文档生成 Agent | 待激活 |
---
*文档结束。等待审批后进入编码阶段。*