Python 教程 10:第一个实用程序
“纸上得来终觉浅,绝知此事要躬行。”
经过前面 9 课的学习,我们已经掌握了 Python 的基础知识。今天,让我们把这些知识串起来,开发一个真正实用的程序:批量文件重命名工具。
1. 项目需求
开发一个命令行工具,能够:
- 批量重命名文件:支持添加前缀、后缀、替换文本
- 过滤文件:支持按扩展名、文件名模式过滤
- 预览模式:先预览修改,确认后再执行
- 撤销功能:记录操作,支持撤销
这个工具很实用,能解决日常工作中的真实问题。
2. 项目结构
file_renamer/
├── file_renamer.py # 主程序
├── renamer.py # 核心重命名逻辑
├── utils.py # 工具函数
└── history.json # 操作历史记录
3. 核心功能实现
3.1 列出目录中的文件
1# utils.py
2import os
3
4def list_files(directory, extension=None, pattern=None):
5 """
6 列出目录中的文件
7
8 Args:
9 directory: 目标目录
10 extension: 文件扩展名过滤(如'.txt')
11 pattern: 文件名模式(简单的包含匹配)
12
13 Returns:
14 文件路径列表
15 """
16 files = []
17
18 for filename in os.listdir(directory):
19 filepath = os.path.join(directory, filename)
20
21 # 只处理文件,忽略目录
22 if not os.path.isfile(filepath):
23 continue
24
25 # 扩展名过滤
26 if extension and not filename.endswith(extension):
27 continue
28
29 # 文件名模式过滤
30 if pattern and pattern not in filename:
31 continue
32
33 files.append(filepath)
34
35 return files
3.2 重命名逻辑
1# renamer.py
2import os
3import re
4
5class FileRenamer:
6 """文件重命名器"""
7
8 def __init__(self, directory):
9 self.directory = directory
10 self.changes = [] # 记录修改
11
12 def add_prefix(self, files, prefix):
13 """添加前缀"""
14 for filepath in files:
15 dirname = os.path.dirname(filepath)
16 filename = os.path.basename(filepath)
17 new_name = prefix + filename
18 new_path = os.path.join(dirname, new_name)
19 self.changes.append((filepath, new_path))
20
21 def add_suffix(self, files, suffix):
22 """添加后缀(在扩展名前)"""
23 for filepath in files:
24 dirname = os.path.dirname(filepath)
25 filename = os.path.basename(filepath)
26 name, ext = os.path.splitext(filename)
27 new_name = name + suffix + ext
28 new_path = os.path.join(dirname, new_name)
29 self.changes.append((filepath, new_path))
30
31 def replace_text(self, files, old_text, new_text):
32 """替换文件名中的文本"""
33 for filepath in files:
34 dirname = os.path.dirname(filepath)
35 filename = os.path.basename(filepath)
36 new_name = filename.replace(old_text, new_text)
37 new_path = os.path.join(dirname, new_name)
38 if filepath != new_path: # 只记录有变化的
39 self.changes.append((filepath, new_path))
40
41 def preview(self):
42 """预览修改"""
43 if not self.changes:
44 print("没有要修改的文件")
45 return
46
47 print(f"\n将要进行 {len(self.changes)} 项修改:")
48 print("-" * 60)
49 for i, (old, new) in enumerate(self.changes, 1):
50 old_name = os.path.basename(old)
51 new_name = os.path.basename(new)
52 print(f"{i}. {old_name} -> {new_name}")
53 print("-" * 60)
54
55 def execute(self):
56 """执行重命名"""
57 if not self.changes:
58 print("没有要执行的操作")
59 return
60
61 success_count = 0
62 for old_path, new_path in self.changes:
63 try:
64 os.rename(old_path, new_path)
65 success_count += 1
66 except Exception as e:
67 print(f"错误:{old_path} -> {e}")
68
69 print(f"\n成功重命名 {success_count}/{len(self.changes)} 个文件")
70
71 # 保存操作历史
72 self.save_history()
73
74 def save_history(self):
75 """保存操作历史(简化版)"""
76 import json
77 from datetime import datetime
78
79 history_file = "history.json"
80
81 # 读取现有历史
82 history = []
83 if os.path.exists(history_file):
84 with open(history_file, 'r', encoding='utf-8') as f:
85 history = json.load(f)
86
87 # 添加新记录
88 history.append({
89 'time': datetime.now().isoformat(),
90 'changes': [(old, new) for old, new in self.changes]
91 })
92
93 # 保存
94 with open(history_file, 'w', encoding='utf-8') as f:
95 json.dump(history, f, indent=2, ensure_ascii=False)
3.3 主程序
1# file_renamer.py
2#!/usr/bin/env python3
3# -*- coding: utf-8 -*-
4
5"""
6文件批量重命名工具
7
8用法:
9 python file_renamer.py
10"""
11
12import os
13from renamer import FileRenamer
14from utils import list_files
15
16def main():
17 print("=" * 60)
18 print("文件批量重命名工具")
19 print("=" * 60)
20
21 # 获取目录
22 directory = input("\n请输入目录路径(留空使用当前目录):").strip()
23 if not directory:
24 directory = "."
25
26 if not os.path.exists(directory):
27 print(f"错误:目录 '{directory}' 不存在")
28 return
29
30 # 获取文件过滤条件
31 extension = input("文件扩展名过滤(如.txt,留空跳过):").strip()
32 if not extension:
33 extension = None
34
35 # 列出文件
36 files = list_files(directory, extension)
37
38 if not files:
39 print("没有找到符合条件的文件")
40 return
41
42 print(f"\n找到 {len(files)} 个文件")
43
44 # 创建重命名器
45 renamer = FileRenamer(directory)
46
47 # 操作菜单
48 while True:
49 print("\n请选择操作:")
50 print("1. 添加前缀")
51 print("2. 添加后缀")
52 print("3. 替换文本")
53 print("4. 预览修改")
54 print("5. 执行重命名")
55 print("0. 退出")
56
57 choice = input("\n请输入选择:").strip()
58
59 if choice == "1":
60 prefix = input("请输入前缀:")
61 renamer.add_prefix(files, prefix)
62 print("✓ 已添加前缀规则")
63
64 elif choice == "2":
65 suffix = input("请输入后缀:")
66 renamer.add_suffix(files, suffix)
67 print("✓ 已添加后缀规则")
68
69 elif choice == "3":
70 old_text = input("请输入要替换的文本:")
71 new_text = input("请输入新文本:")
72 renamer.replace_text(files, old_text, new_text)
73 print("✓ 已添加替换规则")
74
75 elif choice == "4":
76 renamer.preview()
77
78 elif choice == "5":
79 renamer.preview()
80 confirm = input("\n确认执行?(y/N):").strip().lower()
81 if confirm == 'y':
82 renamer.execute()
83 break
84 else:
85 print("已取消")
86
87 elif choice == "0":
88 print("再见!")
89 break
90
91 else:
92 print("无效的选择")
93
94if __name__ == "__main__":
95 main()
4. 使用示例
场景 1:照片重命名
假设有一批照片:
IMG_001.jpg
IMG_002.jpg
IMG_003.jpg
使用工具添加前缀"2024vacation",变成:
2024_vacation_IMG_001.jpg
2024_vacation_IMG_002.jpg
2024_vacation_IMG_003.jpg
场景 2:文档整理
文档文件名:
report_draft.doc
report_final.docx
report_review.docx
替换"report"为"年度总结":
年度总结_draft.doc
年度总结_final.docx
年度总结_review.docx
5. 改进方向
这个基础版本还可以继续改进:
- 正则表达式支持:更强大的匹配和替换
- 序号重命名:按序号重命名文件
- 日期戳支持:在文件名中添加日期
- 递归目录:处理子目录中的文件
- GUI 界面:使用 tkinter 创建图形界面
- 撤销功能完善:真正实现撤销
6. 知识点回顾
这个项目用到了我们学过的:
- 变量和数据类型:字符串、列表、字典
- 控制流程:if、for、while
- 函数:模块化设计
- 字符串操作:替换、分割、拼接
- 文件操作:os 模块、文件读写
- 异常处理:try-except
- 编码规范:遵循 PEP 8
7. 小结
今天我们完成了第一个实用程序!
收获:
- 理解了如何将知识点串联起来
- 学会了模块化设计
- 体验了真实的开发流程:需求 → 设计 → 实现 → 测试
这只是开始。接下来的课程会学习更多高级特性,让你能开发更复杂的应用。
练习题:
- 为程序添加序号重命名功能(如 001、002、003)
- 实现"撤销上一次操作"功能
- 添加进度条显示(使用 tqdm 库)
思考题:
如果要开发一个图形界面版本,你会用什么库?如何设计界面?
本文代码示例: