Python 教程 10:第一个实用程序
“纸上得来终觉浅,绝知此事要躬行。”
经过前面 9 课的学习,我们已经掌握了 Python 的基础知识。今天,让我们把这些知识串起来,开发一个真正实用的程序:批量文件重命名工具。
1. 项目需求
开发一个命令行工具,能够:
- 批量重命名文件:支持添加前缀、后缀、替换文本
- 过滤文件:支持按扩展名、文件名模式过滤
- 预览模式:先预览修改,确认后再执行
- 撤销功能:记录操作,支持撤销
这个工具很实用,能解决日常工作中的真实问题。
2. 项目结构
file_renamer/
├── file_renamer.py # 主程序
├── renamer.py # 核心重命名逻辑
├── utils.py # 工具函数
└── history.json # 操作历史记录
3. 核心功能实现
3.1 列出目录中的文件
# utils.py
import os
def list_files(directory, extension=None, pattern=None):
"""
列出目录中的文件
Args:
directory: 目标目录
extension: 文件扩展名过滤(如'.txt')
pattern: 文件名模式(简单的包含匹配)
Returns:
文件路径列表
"""
files = []
for filename in os.listdir(directory):
filepath = os.path.join(directory, filename)
# 只处理文件,忽略目录
if not os.path.isfile(filepath):
continue
# 扩展名过滤
if extension and not filename.endswith(extension):
continue
# 文件名模式过滤
if pattern and pattern not in filename:
continue
files.append(filepath)
return files
3.2 重命名逻辑
# renamer.py
import os
import re
class FileRenamer:
"""文件重命名器"""
def __init__(self, directory):
self.directory = directory
self.changes = [] # 记录修改
def add_prefix(self, files, prefix):
"""添加前缀"""
for filepath in files:
dirname = os.path.dirname(filepath)
filename = os.path.basename(filepath)
new_name = prefix + filename
new_path = os.path.join(dirname, new_name)
self.changes.append((filepath, new_path))
def add_suffix(self, files, suffix):
"""添加后缀(在扩展名前)"""
for filepath in files:
dirname = os.path.dirname(filepath)
filename = os.path.basename(filepath)
name, ext = os.path.splitext(filename)
new_name = name + suffix + ext
new_path = os.path.join(dirname, new_name)
self.changes.append((filepath, new_path))
def replace_text(self, files, old_text, new_text):
"""替换文件名中的文本"""
for filepath in files:
dirname = os.path.dirname(filepath)
filename = os.path.basename(filepath)
new_name = filename.replace(old_text, new_text)
new_path = os.path.join(dirname, new_name)
if filepath != new_path: # 只记录有变化的
self.changes.append((filepath, new_path))
def preview(self):
"""预览修改"""
if not self.changes:
print("没有要修改的文件")
return
print(f"\n将要进行 {len(self.changes)} 项修改:")
print("-" * 60)
for i, (old, new) in enumerate(self.changes, 1):
old_name = os.path.basename(old)
new_name = os.path.basename(new)
print(f"{i}. {old_name} -> {new_name}")
print("-" * 60)
def execute(self):
"""执行重命名"""
if not self.changes:
print("没有要执行的操作")
return
success_count = 0
for old_path, new_path in self.changes:
try:
os.rename(old_path, new_path)
success_count += 1
except Exception as e:
print(f"错误:{old_path} -> {e}")
print(f"\n成功重命名 {success_count}/{len(self.changes)} 个文件")
# 保存操作历史
self.save_history()
def save_history(self):
"""保存操作历史(简化版)"""
import json
from datetime import datetime
history_file = "history.json"
# 读取现有历史
history = []
if os.path.exists(history_file):
with open(history_file, 'r', encoding='utf-8') as f:
history = json.load(f)
# 添加新记录
history.append({
'time': datetime.now().isoformat(),
'changes': [(old, new) for old, new in self.changes]
})
# 保存
with open(history_file, 'w', encoding='utf-8') as f:
json.dump(history, f, indent=2, ensure_ascii=False)
3.3 主程序
# file_renamer.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件批量重命名工具
用法:
python file_renamer.py
"""
import os
from renamer import FileRenamer
from utils import list_files
def main():
print("=" * 60)
print("文件批量重命名工具")
print("=" * 60)
# 获取目录
directory = input("\n请输入目录路径(留空使用当前目录):").strip()
if not directory:
directory = "."
if not os.path.exists(directory):
print(f"错误:目录 '{directory}' 不存在")
return
# 获取文件过滤条件
extension = input("文件扩展名过滤(如.txt,留空跳过):").strip()
if not extension:
extension = None
# 列出文件
files = list_files(directory, extension)
if not files:
print("没有找到符合条件的文件")
return
print(f"\n找到 {len(files)} 个文件")
# 创建重命名器
renamer = FileRenamer(directory)
# 操作菜单
while True:
print("\n请选择操作:")
print("1. 添加前缀")
print("2. 添加后缀")
print("3. 替换文本")
print("4. 预览修改")
print("5. 执行重命名")
print("0. 退出")
choice = input("\n请输入选择:").strip()
if choice == "1":
prefix = input("请输入前缀:")
renamer.add_prefix(files, prefix)
print("✓ 已添加前缀规则")
elif choice == "2":
suffix = input("请输入后缀:")
renamer.add_suffix(files, suffix)
print("✓ 已添加后缀规则")
elif choice == "3":
old_text = input("请输入要替换的文本:")
new_text = input("请输入新文本:")
renamer.replace_text(files, old_text, new_text)
print("✓ 已添加替换规则")
elif choice == "4":
renamer.preview()
elif choice == "5":
renamer.preview()
confirm = input("\n确认执行?(y/N):").strip().lower()
if confirm == 'y':
renamer.execute()
break
else:
print("已取消")
elif choice == "0":
print("再见!")
break
else:
print("无效的选择")
if __name__ == "__main__":
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 库)
思考题:
如果要开发一个图形界面版本,你会用什么库?如何设计界面?
本文代码示例: