1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
| import os
import re
import time
from xpinyin import Pinyin
from pypinyin import lazy_pinyin, Style
class FileNameProcessor:
"""文件名处理与Markdown生成类"""
def __init__(self, target_dir="raw", output_file="list.md"):
"""
初始化处理器
:param target_dir: 目标处理目录(默认raw)
:param output_file: 生成的Markdown文件路径(默认list.md)
"""
self.target_dir = target_dir
self.output_file = output_file
self.pinyin_converter = Pinyin() # 初始化xpinyin转换器
# 匹配(z-library)的正则(忽略大小写,处理括号/空格变体)
self.zlib_pattern = re.compile(r"\s*\(Z-Library\)\s*", re.IGNORECASE)
# 记录重命名日志(原始名 → 新名)
self.rename_log = []
def _validate_dir(self):
"""验证目标目录是否存在"""
if not os.path.exists(self.target_dir):
raise FileNotFoundError(f"目标目录不存在:{self.target_dir}")
if not os.path.isdir(self.target_dir):
raise NotADirectoryError(f"{self.target_dir} 不是有效的目录")
def _clean_filename(self, filename):
"""
清理文件名中的(z-library)字符
:param filename: 原始文件名
:return: 清理后的文件名
"""
# 分离文件名和扩展名,只清理主文件名
name, ext = os.path.splitext(filename)
clean_name = self.zlib_pattern.sub("", name).strip()
# 避免空文件名(极端情况)
if not clean_name:
clean_name = "unnamed_file"
return f"{clean_name}{ext}"
def _convert_to_pinyin(self, text):
"""
将中文文本转为带声调的拼音(格式:yè-fú-tiān)
:param text: 中文文本(不含扩展名)
:return: 拼音字符串(失败返回原文本)
"""
try:
# 使用pypinyin生成带声调的拼音,用-连接
pinyin_list = lazy_pinyin(text, style=Style.TONE)
return "-".join(pinyin_list)
except Exception as e:
print(f"拼音转换失败(文本:{text}):{str(e)},使用原文本")
return text
def _rename_files(self):
"""
批量重命名目录下的文件:先清理文件名,再转换为拼音(解决死循环核心)
关键优化:1. 先收集所有待重命名文件 2. 避免重复处理 3. 记录重命名日志
"""
print(f"\n开始重命名 {self.target_dir} 目录下的文件...")
# 第一步:收集所有需要处理的文件(避免遍历过程中目录变化导致死循环)
file_paths = []
for root, dirs, files in os.walk(self.target_dir):
for file in files:
# 跳过隐藏文件(如.DS_Store、~$xxx.docx)
if file.startswith('.') or file.startswith('~$'):
continue
file_paths.append((root, file))
# 第二步:批量处理重命名
for root, filename in file_paths:
original_path = os.path.join(root, filename)
# 1. 清理文件名
clean_filename = self._clean_filename(filename)
# 2. 分离名称和扩展名,只转换名称部分为拼音
clean_name, ext = os.path.splitext(clean_filename)
pinyin_name = self._convert_to_pinyin(clean_name)
new_filename = f"{pinyin_name}{ext}"
new_path = os.path.join(root, new_filename)
# 避免重复重命名(如果新名和原名一致则跳过)
if original_path == new_path:
continue
# 处理重名问题(添加序号)
counter = 1
temp_new_path = new_path
while os.path.exists(temp_new_path):
temp_new_filename = f"{pinyin_name}_{counter}{ext}"
temp_new_path = os.path.join(root, temp_new_filename)
counter += 1
new_path = temp_new_path
new_filename = os.path.basename(new_path)
# 执行重命名
try:
os.rename(original_path, new_path)
# 记录重命名日志(原始名 → 新名)
self.rename_log.append((filename, new_filename))
print(f"重命名成功:{filename} → {new_filename}")
except PermissionError:
print(f"权限不足,跳过重命名:{filename}")
self.rename_log.append((filename, f"【重命名失败】{filename}"))
except Exception as e:
print(f"重命名失败 {filename}:{str(e)}")
self.rename_log.append((filename, f"【重命名失败】{filename}"))
print(f"重命名完成!共处理 {len(file_paths)} 个文件,成功 {len([x for x in self.rename_log if '失败' not in x[1]])} 个")
def _get_all_files(self):
"""
递归获取目录下所有文件(过滤文件夹),用于生成Markdown
:return: 元组列表:[(文件相对路径, 文件名, 拼音名称), ...]
"""
file_list = []
for root, dirs, files in os.walk(self.target_dir):
for file in files:
# 跳过隐藏文件(如.DS_Store、~$xxx.docx)
if file.startswith('.') or file.startswith('~$'):
continue
# 构建相对路径
rel_path = os.path.relpath(os.path.join(root, file), self.target_dir)
# 分离名称和扩展名,生成拼音
name, ext = os.path.splitext(file)
name_pinyin = self._convert_to_pinyin(name)
file_list.append((rel_path, file, f"{name_pinyin}{ext}"))
return file_list
def generate_markdown(self):
"""
生成指定格式的Markdown文件(包含重命名日志、拼音列表)
:return: 生成的文件路径
"""
try:
# 1. 验证目录
self._validate_dir()
# 2. 执行文件重命名(先重命名,再生成列表)
self._rename_files()
# 3. 获取处理后的文件列表
print(f"\n开始读取处理后的文件列表:{self.target_dir}")
file_list = self._get_all_files()
if not file_list:
print("警告:目标目录下未找到有效文件")
return None
# 4. 生成Markdown内容
current_time = time.strftime("%a %b %d %H:%M:%S CST %Y", time.localtime())
md_content = [
"# 文件列表(含拼音)",
"",
f"## 处理目录:{self.target_dir}",
f"## 处理时间:{current_time}",
"",
"### 重命名日志(原始名 → 新名)"
]
# 添加重命名日志
if self.rename_log:
for original, new in self.rename_log:
md_content.append(f"- {original} → {new}")
else:
md_content.append("- 无重命名操作")
# 添加带拼音的文件列表
md_content.extend(["", "### 文件列表(带拼音)"])
for idx, (rel_path, filename, pinyin_name) in enumerate(file_list, 1):
md_item = f"{idx}. **{filename}** - 拼音:{pinyin_name}"
md_content.append(md_item)
# 5. 写入Markdown文件
md_content_str = "\n".join(md_content)
with open(self.output_file, 'w', encoding='utf-8') as f:
f.write(md_content_str)
print(f"\nMarkdown文件生成完成:{self.output_file}")
print(f"共处理 {len(file_list)} 个文件")
return self.output_file
except Exception as e:
print(f"生成Markdown失败:{str(e)}")
raise
def main():
"""主函数:程序入口"""
# 配置参数
TARGET_DIR = "raw" # 目标处理目录
OUTPUT_MD = "list.md" # 输出的Markdown文件
# 初始化处理器
processor = FileNameProcessor(target_dir=TARGET_DIR, output_file=OUTPUT_MD)
try:
# 执行完整流程(重命名 + 生成Markdown)
result_path = processor.generate_markdown()
if result_path:
print(f"\n任务完成!生成的Markdown文件:{os.path.abspath(result_path)}")
except FileNotFoundError as e:
print(f"错误:{e},请检查目录是否存在")
except NotADirectoryError as e:
print(f"错误:{e}")
except PermissionError:
print(f"错误:无权限访问 {TARGET_DIR} 或写入 {OUTPUT_MD}")
except ImportError as e:
if "xpinyin" in str(e):
print("错误:未安装xpinyin库,请执行:pip install xpinyin pypinyin")
else:
print(f"错误:缺少依赖库 - {str(e)}")
except Exception as e:
print(f"程序执行出错:{str(e)}")
if __name__ == "__main__":
main()
|