Python教程42:综合项目-图书管理系统

Python教程42:综合项目-图书管理系统 “纸上得来终觉浅,绝知此事要躬行。” 经过第四部分12课的学习,我们掌握了OOP的核心概念。今天通过一个完整的图书管理系统,综合运用所学知识。 1. 项目需求 功能需求 基本功能: 图书管理:添加、删除、搜索、借阅、归还 用户管理:注册、借阅记录 分类管理:按类别组织图书 进阶功能: 数据持久化(JSON) 借阅期限和逾期管理 统计报表 技术要求 使用类和对象 继承和多态 抽象基类 属性管理(@property) 异常处理 文件操作 2. 系统设计 类设计 1Library System 2├── Book(图书基类) 3│ ├── PhysicalBook(实体书) 4│ └── EBook(电子书) 5├── User(用户类) 6├── Library(图书馆类) 7├── BorrowRecord(借阅记录) 8└── Storage(存储类) 3. 核心实现 Book基类 1from abc import ABC, abstractmethod 2from datetime import datetime 3 4class Book(ABC): 5 """图书抽象基类""" 6 7 def __init__(self, isbn, title, author, category): 8 self.isbn = isbn 9 self.title = title 10 self.author = author 11 self.category = category 12 self.is_borrowed = False 13 14 @abstractmethod 15 def get_type(self): 16 """获取图书类型""" 17 pass 18 19 def to_dict(self): 20 """序列化""" 21 return { 22 'isbn': self.isbn, 23 'title': self.title, 24 'author': self.author, 25 'category': self.category, 26 'is_borrowed': self.is_borrowed, 27 'type': self.get_type() 28 } 29 30 def __str__(self): 31 status = "已借出" if self.is_borrowed else "可借阅" 32 return f"{self.title} by {self.author} ({status})" 33 34class PhysicalBook(Book): 35 """实体书""" 36 def __init__(self, isbn, title, author, category, location): 37 super().__init__(isbn, title, author, category) 38 self.location = location # 书架位置 39 40 def get_type(self): 41 return "physical" 42 43 def to_dict(self): 44 data = super().to_dict() 45 data['location'] = self.location 46 return data 47 48class EBook(Book): 49 """电子书""" 50 def __init__(self, isbn, title, author, category, file_size): 51 super().__init__(isbn, title, author, category) 52 self.file_size = file_size # 文件大小(MB) 53 54 def get_type(self): 55 return "ebook" 56 57 def to_dict(self): 58 data = super().to_dict() 59 data['file_size'] = self.file_size 60 return data User类 1class User: 2 """用户类""" 3 4 def __init__(self, user_id, name, email): 5 self.user_id = user_id 6 self.name = name 7 self.email = email 8 self.borrowed_books = [] # ISBN列表 9 10 def can_borrow(self, max_books=5): 11 """检查是否可以借阅""" 12 return len(self.borrowed_books) < max_books 13 14 def borrow_book(self, isbn): 15 """借阅图书""" 16 if isbn not in self.borrowed_books: 17 self.borrowed_books.append(isbn) 18 19 def return_book(self, isbn): 20 """归还图书""" 21 if isbn in self.borrowed_books: 22 self.borrowed_books.remove(isbn) 23 24 def to_dict(self): 25 return { 26 'user_id': self.user_id, 27 'name': self.name, 28 'email': self.email, 29 'borrowed_books': self.borrowed_books 30 } 31 32 def __str__(self): 33 return f"User({self.name}, 已借{len(self.borrowed_books)}本)" BorrowRecord类 1class BorrowRecord: 2 """借阅记录""" 3 4 def __init__(self, user_id, isbn, borrow_date=None): 5 self.user_id = user_id 6 self.isbn = isbn 7 self.borrow_date = borrow_date or datetime.now() 8 self.return_date = None 9 self.due_date = self.borrow_date + timedelta(days=30) 10 11 @property 12 def is_overdue(self): 13 """是否逾期""" 14 if self.return_date: 15 return False 16 return datetime.now() > self.due_date 17 18 def mark_returned(self): 19 """标记为已归还""" 20 self.return_date = datetime.now() 21 22 def to_dict(self): 23 return { 24 'user_id': self.user_id, 25 'isbn': self.isbn, 26 'borrow_date': self.borrow_date.isoformat(), 27 'due_date': self.due_date.isoformat(), 28 'return_date': self.return_date.isoformat() if self.return_date else None 29 } Library类 1class Library: 2 """图书馆类""" 3 4 def __init__(self, name): 5 self.name = name 6 self.books = {} # ISBN -> Book 7 self.users = {} # user_id -> User 8 self.records = [] # BorrowRecord列表 9 10 def add_book(self, book): 11 """添加图书""" 12 if book.isbn in self.books: 13 raise ValueError(f"图书{book.isbn}已存在") 14 self.books[book.isbn] = book 15 16 def remove_book(self, isbn): 17 """删除图书""" 18 if isbn not in self.books: 19 raise ValueError(f"图书{isbn}不存在") 20 if self.books[isbn].is_borrowed: 21 raise ValueError("图书已借出,无法删除") 22 del self.books[isbn] 23 24 def register_user(self, user): 25 """注册用户""" 26 if user.user_id in self.users: 27 raise ValueError(f"用户{user.user_id}已存在") 28 self.users[user.user_id] = user 29 30 def borrow_book(self, user_id, isbn): 31 """借阅图书""" 32 # 验证 33 if user_id not in self.users: 34 raise ValueError("用户不存在") 35 if isbn not in self.books: 36 raise ValueError("图书不存在") 37 38 user = self.users[user_id] 39 book = self.books[isbn] 40 41 if book.is_borrowed: 42 raise ValueError("图书已被借出") 43 if not user.can_borrow(): 44 raise ValueError("借阅数量已达上限") 45 46 # 借阅 47 book.is_borrowed = True 48 user.borrow_book(isbn) 49 record = BorrowRecord(user_id, isbn) 50 self.records.append(record) 51 52 return f"{user.name}成功借阅《{book.title}》" 53 54 def return_book(self, user_id, isbn): 55 """归还图书""" 56 if user_id not in self.users: 57 raise ValueError("用户不存在") 58 if isbn not in self.books: 59 raise ValueError("图书不存在") 60 61 user = self.users[user_id] 62 book = self.books[isbn] 63 64 if not book.is_borrowed: 65 raise ValueError("图书未被借出") 66 67 # 归还 68 book.is_borrowed = False 69 user.return_book(isbn) 70 71 # 更新记录 72 for record in reversed(self.records): 73 if (record.user_id == user_id and 74 record.isbn == isbn and 75 not record.return_date): 76 record.mark_returned() 77 break 78 79 return f"{user.name}成功归还《{book.title}》" 80 81 def search_books(self, keyword): 82 """搜索图书""" 83 results = [] 84 keyword = keyword.lower() 85 for book in self.books.values(): 86 if (keyword in book.title.lower() or 87 keyword in book.author.lower() or 88 keyword in book.category.lower()): 89 results.append(book) 90 return results 91 92 def get_statistics(self): 93 """获取统计信息""" 94 total_books = len(self.books) 95 borrowed = sum(1 for book in self.books.values() if book.is_borrowed) 96 overdue = sum(1 for record in self.records if record.is_overdue) 97 98 return { 99 'total_books': total_books, 100 'available': total_books - borrowed, 101 'borrowed': borrowed, 102 'total_users': len(self.users), 103 'overdue_records': overdue 104 } 4. 使用示例 1# 创建图书馆 2library = Library("市图书馆") 3 4# 添加图书 5book1 = PhysicalBook("978-1", "Python编程", "作者A", "编程", "A-101") 6book2 = EBook("978-2", "数据结构", "作者B", "编程", 15.5) 7library.add_book(book1) 8library.add_book(book2) 9 10# 注册用户 11user = User("U001", "张三", "zhang@example.com") 12library.register_user(user) 13 14# 借阅流程 15print(library.borrow_book("U001", "978-1")) 16print(library.borrow_book("U001", "978-2")) 17 18# 搜索 19results = library.search_books("Python") 20for book in results: 21 print(book) 22 23# 统计 24stats = library.get_statistics() 25print(f"总藏书:{stats['total_books']}") 26print(f"可借阅:{stats['available']}") 27print(f"已借出:{stats['borrowed']}") 28 29# 归还 30print(library.return_book("U001", "978-1")) 5. 知识点回顾 这个项目运用了: ...

2026-01-08 · 5 min · 874 words · 老墨

Python教程30:综合项目-任务管理器

Python教程30:综合项目-任务管理器 “纸上得来终觉浅,绝知此事要躬行。” 经过第三部分13课的学习,我们掌握了函数、模块、文件操作、异常处理、测试等核心知识。今天我们通过一个完整项目——命令行任务管理器,把这些知识综合应用起来。 1. 项目需求 功能需求 开发一个命令行任务管理器(Todo List),支持: 基本功能 添加任务 查看任务列表 标记任务完成 删除任务 进阶功能 任务优先级(高、中、低) 任务分类(工作、生活、学习) 截止日期 数据持久化(保存到文件) 额外功能 搜索任务 统计信息 导入/导出 技术要求 使用函数和类组织代码 模块化设计 完善的异常处理 文件操作(JSON格式存储) 单元测试 命令行交互 2. 项目结构 1task_manager/ 2├── task_manager/ # 主包 3│ ├── __init__.py 4│ ├── task.py # 任务类 5│ ├── manager.py # 管理器类 6│ ├── storage.py # 存储模块 7│ └── utils.py # 工具函数 8├── tests/ # 测试 9│ ├── __init__.py 10│ ├── test_task.py 11│ ├── test_manager.py 12│ └── test_storage.py 13├── main.py # 主程序入口 14├── README.md 15└── requirements.txt 3. 核心模块实现 3.1 任务类(task.py) 1""" 2任务类模块 3- 定义Task类表示单个任务 4- 应用:类、属性、方法 5""" 6 7from datetime import datetime 8from enum import Enum 9 10class Priority(Enum): 11 """ 12 任务优先级枚举 13 - 使用Enum定义常量 14 - 避免魔法数字 15 """ 16 LOW = 1 17 MEDIUM = 2 18 HIGH = 3 19 20class Category(Enum): 21 """任务分类""" 22 WORK = "工作" 23 LIFE = "生活" 24 STUDY = "学习" 25 OTHER = "其他" 26 27class Task: 28 """ 29 任务类 30 31 Attributes: 32 title: 任务标题 33 description: 任务描述 34 priority: 优先级 35 category: 分类 36 due_date: 截止日期 37 completed: 是否完成 38 created_at: 创建时间 39 """ 40 41 def __init__(self, title, description="", 42 priority=Priority.MEDIUM, 43 category=Category.OTHER, 44 due_date=None): 45 """ 46 初始化任务 47 48 Args: 49 title: 任务标题(必需) 50 description: 任务描述 51 priority: 优先级(默认中等) 52 category: 分类(默认其他) 53 due_date: 截止日期(datetime对象) 54 55 Raises: 56 ValueError: 标题为空时 57 """ 58 if not title: 59 raise ValueError("任务标题不能为空") 60 61 self.title = title 62 self.description = description 63 self.priority = priority 64 self.category = category 65 self.due_date = due_date 66 self.completed = False 67 self.created_at = datetime.now() 68 69 def mark_complete(self): 70 """标记任务完成""" 71 self.completed = True 72 73 def mark_incomplete(self): 74 """标记任务未完成""" 75 self.completed = False 76 77 def to_dict(self): 78 """ 79 转换为字典(用于JSON序列化) 80 81 Returns: 82 dict: 任务的字典表示 83 """ 84 return { 85 "title": self.title, 86 "description": self.description, 87 "priority": self.priority.value, 88 "category": self.category.value, 89 "due_date": self.due_date.isoformat() if self.due_date else None, 90 "completed": self.completed, 91 "created_at": self.created_at.isoformat() 92 } 93 94 @classmethod 95 def from_dict(cls, data): 96 """ 97 从字典创建任务(用于JSON反序列化) 98 99 Args: 100 data: 任务字典 101 102 Returns: 103 Task: 任务对象 104 """ 105 task = cls( 106 title=data["title"], 107 description=data.get("description", ""), 108 priority=Priority(data.get("priority", 2)), 109 category=Category(data.get("category", "其他")) 110 ) 111 112 if data.get("due_date"): 113 task.due_date = datetime.fromisoformat(data["due_date"]) 114 115 task.completed = data.get("completed", False) 116 task.created_at = datetime.fromisoformat(data["created_at"]) 117 118 return task 119 120 def __str__(self): 121 """字符串表示""" 122 status = "✓" if self.completed else " " 123 priority_symbols = { 124 Priority.LOW: "▽", 125 Priority.MEDIUM: "◇", 126 Priority.HIGH: "▲" 127 } 128 129 return f"[{status}] {priority_symbols[self.priority]} {self.title}" 130 131 def __repr__(self): 132 """开发者表示""" 133 return f"Task(title='{self.title}', completed={self.completed})" 3.2 存储模块(storage.py) 1""" 2存储模块 3- 负责任务数据的持久化 4- 应用:文件操作、JSON、异常处理 5""" 6 7import json 8import os 9from pathlib import Path 10from typing import List 11from task import Task 12 13class TaskStorage: 14 """ 15 任务存储类 16 - 使用JSON格式存储 17 - 包含完整的异常处理 18 """ 19 20 def __init__(self, file_path="tasks.json"): 21 """ 22 初始化存储 23 24 Args: 25 file_path: 存储文件路径 26 """ 27 self.file_path = Path(file_path) 28 self._ensure_file_exists() 29 30 def _ensure_file_exists(self): 31 """确保存储文件存在""" 32 if not self.file_path.exists(): 33 self.file_path.write_text("[]", encoding="utf-8") 34 35 def save_tasks(self, tasks: List[Task]): 36 """ 37 保存任务列表 38 39 Args: 40 tasks: 任务列表 41 42 Raises: 43 IOError: 文件写入失败时 44 """ 45 try: 46 data = [task.to_dict() for task in tasks] 47 48 # 使用with确保文件正确关闭 49 with open(self.file_path, "w", encoding="utf-8") as f: 50 json.dump(data, f, ensure_ascii=False, indent=2) 51 52 except Exception as e: 53 raise IOError(f"保存任务失败:{e}") 54 55 def load_tasks(self) -> List[Task]: 56 """ 57 加载任务列表 58 59 Returns: 60 List[Task]: 任务列表 61 62 Raises: 63 IOError: 文件读取失败时 64 """ 65 try: 66 with open(self.file_path, encoding="utf-8") as f: 67 data = json.load(f) 68 69 return [Task.from_dict(item) for item in data] 70 71 except json.JSONDecodeError as e: 72 raise IOError(f"JSON解析失败:{e}") 73 except Exception as e: 74 raise IOError(f"加载任务失败:{e}") 75 76 def backup(self, backup_path=None): 77 """ 78 备份任务数据 79 80 Args: 81 backup_path: 备份文件路径 82 """ 83 if backup_path is None: 84 backup_path = f"{self.file_path}.backup" 85 86 import shutil 87 shutil.copy(self.file_path, backup_path) 3.3 任务管理器(manager.py) 1""" 2任务管理器 3- 核心业务逻辑 4- 应用:类、方法、列表操作 5""" 6 7from typing import List, Optional 8from task import Task, Priority, Category 9from storage import TaskStorage 10 11class TaskManager: 12 """ 13 任务管理器 14 - 管理任务的CRUD操作 15 - 提供搜索、统计等功能 16 """ 17 18 def __init__(self, storage: TaskStorage): 19 """ 20 初始化管理器 21 22 Args: 23 storage: 存储对象 24 """ 25 self.storage = storage 26 self.tasks: List[Task] = [] 27 self.load() 28 29 def load(self): 30 """加载任务""" 31 try: 32 self.tasks = self.storage.load_tasks() 33 except IOError as e: 34 print(f"警告:{e}") 35 self.tasks = [] 36 37 def save(self): 38 """保存任务""" 39 try: 40 self.storage.save_tasks(self.tasks) 41 except IOError as e: 42 print(f"错误:{e}") 43 44 def add_task(self, task: Task): 45 """添加任务""" 46 self.tasks.append(task) 47 self.save() 48 49 def get_all_tasks(self) -> List[Task]: 50 """获取所有任务""" 51 return self.tasks 52 53 def get_task(self, index: int) -> Optional[Task]: 54 """ 55 获取指定任务 56 57 Args: 58 index: 任务索引 59 60 Returns: 61 Task或None 62 """ 63 if 0 <= index < len(self.tasks): 64 return self.tasks[index] 65 return None 66 67 def complete_task(self, index: int) -> bool: 68 """标记任务完成""" 69 task = self.get_task(index) 70 if task: 71 task.mark_complete() 72 self.save() 73 return True 74 return False 75 76 def delete_task(self, index: int) -> bool: 77 """删除任务""" 78 if 0 <= index < len(self.tasks): 79 self.tasks.pop(index) 80 self.save() 81 return True 82 return False 83 84 def search_tasks(self, keyword: str) -> List[Task]: 85 """ 86 搜索任务 87 88 Args: 89 keyword: 关键词 90 91 Returns: 92 匹配的任务列表 93 """ 94 keyword = keyword.lower() 95 return [ 96 task for task in self.tasks 97 if keyword in task.title.lower() 98 or keyword in task.description.lower() 99 ] 100 101 def get_statistics(self) -> dict: 102 """ 103 获取统计信息 104 105 Returns: 106 统计字典 107 """ 108 total = len(self.tasks) 109 completed = sum(1 for task in self.tasks if task.completed) 110 pending = total - completed 111 112 by_priority = { 113 Priority.HIGH: 0, 114 Priority.MEDIUM: 0, 115 Priority.LOW: 0 116 } 117 118 for task in self.tasks: 119 if not task.completed: 120 by_priority[task.priority] += 1 121 122 return { 123 "total": total, 124 "completed": completed, 125 "pending": pending, 126 "high_priority": by_priority[Priority.HIGH], 127 "medium_priority": by_priority[Priority.MEDIUM], 128 "low_priority": by_priority[Priority.LOW] 129 } 3.4 主程序(main.py) 1""" 2主程序入口 3- 命令行交互界面 4- 应用:函数、控制流程、异常处理 5""" 6 7from task import Task, Priority, Category 8from manager import TaskManager 9from storage import TaskStorage 10from datetime import datetime 11 12def print_menu(): 13 """打印菜单""" 14 print("\n" + "=" * 50) 15 print("任务管理器") 16 print("=" * 50) 17 print("1. 查看所有任务") 18 print("2. 添加任务") 19 print("3. 完成任务") 20 print("4. 删除任务") 21 print("5. 搜索任务") 22 print("6. 统计信息") 23 print("0. 退出") 24 print("=" * 50) 25 26def display_tasks(tasks): 27 """显示任务列表""" 28 if not tasks: 29 print("没有任务") 30 return 31 32 print("\n任务列表:") 33 for i, task in enumerate(tasks): 34 print(f"{i}. {task}") 35 if task.due_date: 36 print(f" 截止:{task.due_date.strftime('%Y-%m-%d')}") 37 38def add_task_interactive(manager: TaskManager): 39 """交互式添加任务""" 40 print("\n添加新任务") 41 42 title = input("标题:").strip() 43 if not title: 44 print("标题不能为空") 45 return 46 47 description = input("描述(可选):").strip() 48 49 print("优先级:1-低 2-中 3-高") 50 priority_input = input("选择(默认2):").strip() or "2" 51 priority = Priority(int(priority_input)) 52 53 try: 54 task = Task( 55 title=title, 56 description=description, 57 priority=priority 58 ) 59 manager.add_task(task) 60 print("✓ 任务已添加") 61 62 except ValueError as e: 63 print(f"错误:{e}") 64 65def main(): 66 """主函数""" 67 print("欢迎使用任务管理器") 68 69 # 初始化 70 storage = TaskStorage() 71 manager = TaskManager(storage) 72 73 while True: 74 print_menu() 75 choice = input("\n请选择操作:").strip() 76 77 try: 78 if choice == "1": 79 display_tasks(manager.get_all_tasks()) 80 81 elif choice == "2": 82 add_task_interactive(manager) 83 84 elif choice == "3": 85 display_tasks(manager.get_all_tasks()) 86 index = int(input("请输入任务编号:")) 87 if manager.complete_task(index): 88 print("✓ 任务已完成") 89 else: 90 print("无效的任务编号") 91 92 elif choice == "4": 93 display_tasks(manager.get_all_tasks()) 94 index = int(input("请输入任务编号:")) 95 if manager.delete_task(index): 96 print("✓ 任务已删除") 97 else: 98 print("无效的任务编号") 99 100 elif choice == "5": 101 keyword = input("请输入搜索关键词:") 102 results = manager.search_tasks(keyword) 103 display_tasks(results) 104 105 elif choice == "6": 106 stats = manager.get_statistics() 107 print(f"\n总任务数:{stats['total']}") 108 print(f"已完成:{stats['completed']}") 109 print(f"待完成:{stats['pending']}") 110 print(f" 高优先级:{stats['high_priority']}") 111 print(f" 中优先级:{stats['medium_priority']}") 112 print(f" 低优先级:{stats['low_priority']}") 113 114 elif choice == "0": 115 print("再见!") 116 break 117 118 else: 119 print("无效的选择") 120 121 except Exception as e: 122 print(f"发生错误:{e}") 123 import traceback 124 traceback.print_exc() 125 126if __name__ == "__main__": 127 main() 4. 单元测试 1# tests/test_task.py 2import unittest 3from datetime import datetime 4from task import Task, Priority, Category 5 6class TestTask(unittest.TestCase): 7 """测试Task类""" 8 9 def test_task_creation(self): 10 """测试任务创建""" 11 task = Task("测试任务") 12 13 self.assertEqual(task.title, "测试任务") 14 self.assertFalse(task.completed) 15 self.assertEqual(task.priority, Priority.MEDIUM) 16 17 def test_empty_title_raises_error(self): 18 """测试空标题抛出异常""" 19 with self.assertRaises(ValueError): 20 Task("") 21 22 def test_mark_complete(self): 23 """测试标记完成""" 24 task = Task("测试") 25 task.mark_complete() 26 27 self.assertTrue(task.completed) 28 29 def test_to_dict_and_from_dict(self): 30 """测试序列化/反序列化""" 31 task = Task("测试", priority=Priority.HIGH) 32 33 data = task.to_dict() 34 restored = Task.from_dict(data) 35 36 self.assertEqual(restored.title, task.title) 37 self.assertEqual(restored.priority, task.priority) 38 39if __name__ == "__main__": 40 unittest.main() 5. 知识点回顾 这个项目综合运用了: ...

2025-03-20 · 8 min · 1551 words · 老墨

Python教程10:第一个实用程序

Python 教程 10:第一个实用程序 “纸上得来终觉浅,绝知此事要躬行。” 经过前面 9 课的学习,我们已经掌握了 Python 的基础知识。今天,让我们把这些知识串起来,开发一个真正实用的程序:批量文件重命名工具。 1. 项目需求 开发一个命令行工具,能够: 批量重命名文件:支持添加前缀、后缀、替换文本 过滤文件:支持按扩展名、文件名模式过滤 预览模式:先预览修改,确认后再执行 撤销功能:记录操作,支持撤销 这个工具很实用,能解决日常工作中的真实问题。 2. 项目结构 1file_renamer/ 2├── file_renamer.py # 主程序 3├── renamer.py # 核心重命名逻辑 4├── utils.py # 工具函数 5└── 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:照片重命名 假设有一批照片: ...

2024-03-18 · 4 min · 787 words · 老墨