本文目录导读:

我来教你编写目录树生成脚本,提供多个版本供你选择。
Python版本(功能最完整)
#!/usr/bin/env python3
"""
目录树生成脚本
支持文件/文件夹图标,过滤git等目录
"""
import os
import sys
from pathlib import Path
def generate_tree(directory, prefix="", show_hidden=False, max_depth=None, current_depth=0):
"""
生成目录树结构
"""
if max_depth is not None and current_depth > max_depth:
return
# 获取目录内容并排序
try:
entries = sorted(Path(directory).iterdir(), key=lambda x: (not x.is_dir(), x.name.lower()))
except PermissionError:
print(f"{prefix}└── [权限不足]")
return
# 过滤文件
filtered_entries = []
for entry in entries:
name = entry.name
# 跳过隐藏文件
if not show_hidden and name.startswith('.'):
continue
# 跳过特定目录
if name in ['__pycache__', 'node_modules', '.git', '.svn', '.DS_Store']:
continue
filtered_entries.append(entry)
# 打印目录树
for i, entry in enumerate(filtered_entries):
is_last = (i == len(filtered_entries) - 1)
connector = "└── " if is_last else "├── "
if entry.is_dir():
print(f"{prefix}{connector}{'📁 '}{entry.name}/")
# 递归处理子目录
extension = " " if is_last else "│ "
generate_tree(
entry,
prefix + extension,
show_hidden,
max_depth,
current_depth + 1
)
else:
# 显示文件大小
try:
size = entry.stat().st_size
size_str = format_size(size)
print(f"{prefix}{connector}{'📄 '}{entry.name} ({size_str})")
except:
print(f"{prefix}{connector}{'📄 '}{entry.name}")
def format_size(bytes):
"""格式化文件大小"""
for unit in ['B', 'KB', 'MB', 'GB']:
if bytes < 1024:
return f"{bytes:.1f} {unit}"
bytes /= 1024
return f"{bytes:.1f} TB"
def main():
import argparse
parser = argparse.ArgumentParser(description='生成目录树结构')
parser.add_argument('directory', nargs='?', default='.',
help='要分析的目录路径 (默认: 当前目录)')
parser.add_argument('-a', '--all', action='store_true',
help='显示隐藏文件')
parser.add_argument('-d', '--depth', type=int, default=None,
help='最大深度')
parser.add_argument('-o', '--output', type=str,
help='输出到文件')
parser.add_argument('--no-icon', action='store_true',
help='不显示图标')
args = parser.parse_args()
if not os.path.exists(args.directory):
print(f"错误: 目录 '{args.directory}' 不存在")
sys.exit(1)
# 重定向输出到文件
if args.output:
import io
old_stdout = sys.stdout
sys.stdout = io.StringIO()
print(f"📂 {os.path.abspath(args.directory)}/\n")
generate_tree(args.directory, show_hidden=args.all, max_depth=args.depth)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(sys.stdout.getvalue())
sys.stdout = old_stdout
print(f"目录树已保存到: {args.output}")
if __name__ == "__main__":
main()
Bash版本(简单实用)
#!/bin/bash
# tree.sh - 简易目录树生成脚本
# 使用tree命令(如果存在)
if command -v tree &> /dev/null; then
tree -L ${1:-3} --charset utf-8
exit 0
fi
# 自定义实现
list_files() {
local dir="$1"
local prefix="$2"
local depth="${3:-0}"
local max_depth="${4:-3}"
if [ "$depth" -ge "$max_depth" ]; then
return
fi
# 获取文件列表
local files=("$dir"/*)
local total=${#files[@]}
local count=0
for file in "${files[@]}"; do
count=$((count + 1))
local name=$(basename "$file")
# 跳过隐藏文件和特定目录
[[ "$name" == .* ]] && continue
[[ "$name" == "node_modules" ]] && continue
[[ "$name" == "__pycache__" ]] && continue
if [ $count -eq $total ]; then
echo "${prefix}└── $name"
if [ -d "$file" ]; then
list_files "$file" "${prefix} " $((depth + 1)) $max_depth
fi
else
echo "${prefix}├── $name"
if [ -d "$file" ]; then
list_files "$file" "${prefix}│ " $((depth + 1)) $max_depth
fi
fi
done
}
# 主程序
ROOT_DIR="${1:-.}"
MAX_DEPTH="${2:-3}"
echo "📂 $(realpath "$ROOT_DIR")/"
list_files "$ROOT_DIR" "" 0 "$MAX_DEPTH"
Node.js版本(跨平台)
#!/usr/bin/env node
// tree.js - Node.js目录树生成
const fs = require('fs');
const path = require('path');
class DirectoryTree {
constructor(options = {}) {
this.showHidden = options.showHidden || false;
this.maxDepth = options.maxDepth || Infinity;
this.icons = options.icons !== false;
}
generate(dirPath, prefix = '', depth = 0) {
if (depth > this.maxDepth) return;
let entries;
try {
entries = fs.readdirSync(dirPath, { withFileTypes: true });
} catch (err) {
console.log(`${prefix}└── [${err.message}]`);
return;
}
// 过滤和排序
entries = entries
.filter(entry => {
if (!this.showHidden && entry.name.startsWith('.')) return false;
if (['node_modules', '__pycache__', '.git'].includes(entry.name)) return false;
return true;
})
.sort((a, b) => {
if (a.isDirectory() && !b.isDirectory()) return -1;
if (!a.isDirectory() && b.isDirectory()) return 1;
return a.name.localeCompare(b.name);
});
entries.forEach((entry, index) => {
const isLast = index === entries.length - 1;
const connector = isLast ? '└── ' : '├── ';
const icon = this.icons ? (entry.isDirectory() ? '📁 ' : '📄 ') : '';
if (entry.isDirectory()) {
console.log(`${prefix}${connector}${icon}${entry.name}/`);
const extension = isLast ? ' ' : '│ ';
this.generate(
path.join(dirPath, entry.name),
prefix + extension,
depth + 1
);
} else {
const stats = fs.statSync(path.join(dirPath, entry.name));
const size = this.formatSize(stats.size);
console.log(`${prefix}${connector}${icon}${entry.name} (${size})`);
}
});
}
formatSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
for (const unit of units) {
if (size < 1024) return `${size.toFixed(1)} ${unit}`;
size /= 1024;
}
return `${size.toFixed(1)} TB`;
}
}
// 主程序
const args = process.argv.slice(2);
const dirPath = args[0] || '.';
const maxDepth = parseInt(args[1]) || 3;
const tree = new DirectoryTree({
showHidden: args.includes('--all'),
maxDepth: maxDepth,
icons: !args.includes('--no-icon')
});
console.log(`📂 ${path.resolve(dirPath)}/\n`);
tree.generate(dirPath);
使用示例
Python版本:
# 基本使用 python tree.py # 指定目录 python tree.py /path/to/directory # 显示隐藏文件 python tree.py -a # 限制深度 python tree.py -d 2 # 输出到文件 python tree.py -o output.txt # 查看帮助 python tree.py -h
Bash版本:
# 添加执行权限 chmod +x tree.sh # 使用(参数:目录 深度) ./tree.sh /path/to/directory 2
Node.js版本:
# 添加执行权限 chmod +x tree.js # 使用 node tree.js /path/to/directory 2 --all
输出示例
📂 /home/user/project/
├── 📁 src/
│ ├── 📁 components/
│ │ ├── 📄 App.js (2.3 KB)
│ │ └── 📄 Header.js (1.1 KB)
│ ├── 📄 index.js (0.5 KB)
│ └── 📄 styles.css (3.2 KB)
├── 📁 public/
│ └── 📄 index.html (1.0 KB)
├── 📄 package.json (0.8 KB)
└── 📄 README.md (2.1 KB)
选择最适合你需求的版本,建议使用Python版本功能最完整,Bash版本最轻量,Node.js版本适合前端开发者。