引言
在Python入门到精通(三)中,我们了解Python模块、输入输出以及文件读写操作。
现在编写一个小游戏对文件读写、输入输出进行简单应用,巩固基础,加深理解。
文章目录
简易文件管理器说明
一、主要功能
实现了一个基于命令行的简单文件管理器。
主要功能包括:
1)文件/目录浏览 - 显示当前目录内容
2)目录导航 - 切换目录、返回上一级
3)文件操作 - 创建文件/目录、删除项目
4)搜索功能 - 在目录树中搜索文件/目录
5)书签系统 - 保存常用目录路径
6)配置持久化 - 保存书签到JSON文件
7)历史记录 - 记录访问过的目录(最多10条)
二、实现思路和步骤
2.1 整体架构
面向对象设计:使用SimpleFileManager类封装所有功能
配置管理:使用JSON文件存储书签等配置信息
命令行交互:通过简单的命令语法进行用户交互
路径管理:使用pathlib.Path处理跨平台路径问题
2.2 核心实现步骤
1)初始化阶段
· 设置基础工作目录
· 初始化历史记录和书签字典
· 加载现有配置文件
python
def __init__(self, base_dir="."):
# 初始化基础目录,确保是绝对路径
self.base_dir = Path(base_dir).resolve()
# 历史记录栈,用于返回上一级目录
self.history = []
# 书签字典:名称->路径
self.bookmarks = {}
# 加载已有配置
self.load_config()
def load_config(self):
config_file = self.base_dir / ".file_manager.json" # /运算符在路径操作中用于连接路径
if config_file.exists(): # 如果文件存在
try:
# 读取JSON配置
with open(config_file, "r", encoding="utf-8") as f:
config = json.load(f)
# 获取书签配置
self.bookmarks = config.get("bookmarks", {})
except Exception as e:
print(f"加载配置失败: {e}")
2)文件系统操作
· 使用os.walk()进行目录遍历
· 使用pathlib模块方法来删除文件
· 使用shutil进行递归删除操作
python
# 在当前目录树中搜索文件/目录
def search_files(self, pattern: str):
matches = [] # 符合检索的文件/目录
pattern_lower = pattern.lower() # 不区分大小写搜索
# 递归遍历目录树
for root, dirs, files in os.walk(self.base_dir):
# 排除隐藏目录(不搜索隐藏目录)
dirs[:] = [d for d in dirs if not d.startswith(".")] #目录名以.开头的为隐藏目录
# 搜索文件和目录名
for name in files + dirs:
if pattern_lower in name.lower():
full_path = Path(root) / name
# 计算相对于当前目录的路径
rel_path = full_path.relative_to(self.base_dir)
file_type = "目录" if full_path.is_dir() else "文件"
matches.append({
"name": str(rel_path),
"type": file_type
})
# 显示搜索结果
if matches:
print(f"\n找到 {len(matches)} 个匹配项:")
for match in matches[:20]: # 最多显示20个结果
print(f"[{match['type']}] {match['name']}")
if len(matches) > 20:
print(f"... 还有 {len(matches) - 20} 个结果未显示")
else:
print("未找到匹配项")
# 删除文件或目录
def delete_item(self, name: str, confirm=True):
target = self.base_dir / name
if not target.exists():
print(f"项目不存在: {name}")
return False
# 确认删除(如果需要)
if confirm:
confirm = input(f"确定删除 {name} 吗?(y/N): ").strip().lower()
if confirm != "y":
print("取消删除")
return False
try:
# 递归删除目录或删除文件
if target.is_dir(): #is_dir()和unlink()方法属于pathlib模块方法
shutil.rmtree(target) # 递归删除整个目录树
else:
target.unlink() # 删除文件
print(f"已删除: {name}")
return True
except Exception as e:
print(f"删除失败: {e}")
return False
3)用户界面
· 实时显示当前目录路径
· 格式化输出文件信息(名称、类型、大小、修改时间)
· 提供简洁的输入提示
python
# 格式化显示文件列表
def display_files(self, files: List[Dict[str, Any]]):
print(f"\n当前目录: {self.base_dir}")
print("=" * 80)
# 表头
print(f"{'名称':<30} {'类型':<10} {'大小':<10} {'修改时间':<20}")
print("-" * 80)
# 显示每个文件的信息
for file in files:
size_str = self.format_size(file["size"])
time_str = file["modified"].strftime("%Y-%m-%d %H:%M:%S")
print(f"{file['name']:<30} {file['type']:<10} {size_str:<10} {time_str:<20}")
print("=" * 80)
print(f"总计: {len(files)} 个项目")
4)持久化存储
· 使用JSON格式存储书签配置
· 自动保存到隐藏的配置文件.file_manager.json
python
# 保存配置到JSON文件
def save_config(self):
config_file = self.base_dir / ".file_manager.json"
config = {"bookmarks": self.bookmarks}
try:
with open(config_file, "w", encoding="utf-8") as f:
# 格式化保存JSON,确保中文正常显示
json.dump(config, f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"保存配置失败: {e}")
三、代码实现及注释
python
import os
import shutil
import json
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Any
# 简易文件管理器类
class SimpleFileManager:
def __init__(self, base_dir="."):
# 初始化基础目录,确保是绝对路径
self.base_dir = Path(base_dir).resolve()
# 历史记录栈,用于返回上一级目录
self.history = []
# 书签字典:名称->路径
self.bookmarks = {}
# 加载已有配置
self.load_config()
# 加载配置文件
def load_config(self):
config_file = self.base_dir / ".file_manager.json"
if config_file.exists():
try:
# 读取JSON配置
with open(config_file, "r", encoding="utf-8") as f:
config = json.load(f)
# 获取书签配置
self.bookmarks = config.get("bookmarks", {})
except Exception as e:
print(f"加载配置失败: {e}")
# 保存配置到JSON文件
def save_config(self):
config_file = self.base_dir / ".file_manager.json"
config = {"bookmarks": self.bookmarks}
try:
with open(config_file, "w", encoding="utf-8") as f:
# 格式化保存JSON,确保中文正常显示
json.dump(config, f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"保存配置失败: {e}")
# 获取当前目录下的文件和目录列表
def get_current_files(self, show_hidden=False) -> List[Dict[str, Any]]:
files = []
# 遍历当前目录
for item in self.base_dir.iterdir():
# 根据参数决定是否显示隐藏文件
if not show_hidden and item.name.startswith("."):
continue
try:
# 获取文件状态信息
stat = item.stat()
file_info = {
"name": item.name,
"type": "目录" if item.is_dir() else "文件",
"size": stat.st_size,
"modified": datetime.fromtimestamp(stat.st_mtime),
"path": str(item)
}
files.append(file_info)
except OSError:
# 忽略权限不足等错误
continue
# 排序:目录在前,文件在后,按名称不区分大小写排序
files.sort(key=lambda x: (x["type"] != "目录", x["name"].lower()))
return files
# 格式化显示文件列表
def display_files(self, files: List[Dict[str, Any]]):
print(f"\n当前目录: {self.base_dir}")
print("=" * 80)
# 表头
print(f"{'名称':<30} {'类型':<10} {'大小':<10} {'修改时间':<20}")
print("-" * 80)
# 显示每个文件的信息
for file in files:
size_str = self.format_size(file["size"])
time_str = file["modified"].strftime("%Y-%m-%d %H:%M:%S")
print(f"{file['name']:<30} {file['type']:<10} {size_str:<10} {time_str:<20}")
print("=" * 80)
print(f"总计: {len(files)} 个项目")
# 将字节数转换为易读的大小表示
def format_size(self, size_bytes: int) -> str:
for unit in ["B", "KB", "MB", "GB", "TB"]:
if size_bytes < 1024.0:
return f"{size_bytes:.1f}{unit}"
size_bytes /= 1024.0
return f"{size_bytes:.1f}PB"
# 切换到指定目录
def navigate(self, target: str):
# 处理相对路径
target_path = (self.base_dir / target).resolve()
# 特殊处理:返回上级目录
if target == "..":
target_path = self.base_dir.parent
# 验证目录存在且可访问
if target_path.exists() and target_path.is_dir():
# 保存当前目录到历史记录
self.history.append(str(self.base_dir))
# 限制历史记录长度
if len(self.history) > 10:
self.history.pop(0)
# 更新当前目录
self.base_dir = target_path
return True
else:
print(f"目录不存在或无权限: {target}")
return False
# 返回到历史记录中的上一个目录
def go_back(self):
if self.history:
self.base_dir = Path(self.history.pop())
return True
return False
# 创建空文件
def create_file(self, filename: str):
""""""
filepath = self.base_dir / filename
try:
filepath.touch() # 创建文件
print(f"文件已创建: {filename}")
except Exception as e:
print(f"创建文件失败: {e}")
# 创建目录
def create_dir(self, dirname: str):
dirpath = self.base_dir / dirname
try:
dirpath.mkdir(exist_ok=True) # 如果已存在则不报错
print(f"目录已创建: {dirname}")
except Exception as e:
print(f"创建目录失败: {e}")
# 删除文件或目录
def delete_item(self, name: str, confirm=True):
target = self.base_dir / name
if not target.exists():
print(f"项目不存在: {name}")
return False
# 确认删除(如果需要)
if confirm:
confirm = input(f"确定删除 {name} 吗?(y/N): ").strip().lower()
if confirm != "y":
print("取消删除")
return False
try:
# 递归删除目录或删除文件
if target.is_dir():
shutil.rmtree(target)
else:
target.unlink()
print(f"已删除: {name}")
return True
except Exception as e:
print(f"删除失败: {e}")
return False
# 添加书签:将当前目录或指定路径保存为书签
def add_bookmark(self, name: str, path: str = None):
if path is None:
path = str(self.base_dir)
self.bookmarks[name] = path
self.save_config() # 保存到配置文件
print(f"书签已添加: {name} -> {path}")
# 跳转到书签指向的目录
def jump_to_bookmark(self, name: str):
if name in self.bookmarks:
target = Path(self.bookmarks[name])
if target.exists() and target.is_dir():
# 保存当前目录到历史记录
self.history.append(str(self.base_dir))
self.base_dir = target
print(f"已跳转到书签: {name}")
return True
else:
print(f"书签指向的目录不存在: {self.bookmarks[name]}")
else:
print(f"书签不存在: {name}")
return False
# 显示所有书签
def show_bookmarks(self):
if not self.bookmarks:
print("暂无书签")
return
print("\n书签列表:")
for name, path in self.bookmarks.items():
print(f" {name}: {path}")
# 在当前目录树中搜索文件/目录
def search_files(self, pattern: str):
matches = []
pattern_lower = pattern.lower() # 不区分大小写搜索
# 递归遍历目录树
for root, dirs, files in os.walk(self.base_dir):
# 排除隐藏目录(不搜索隐藏目录)
dirs[:] = [d for d in dirs if not d.startswith(".")]
# 搜索文件和目录名
for name in files + dirs:
if pattern_lower in name.lower():
full_path = Path(root) / name
# 计算相对于当前目录的路径
rel_path = full_path.relative_to(self.base_dir)
file_type = "目录" if full_path.is_dir() else "文件"
matches.append({
"name": str(rel_path),
"type": file_type
})
# 显示搜索结果
if matches:
print(f"\n找到 {len(matches)} 个匹配项:")
for match in matches[:20]: # 最多显示20个结果
print(f" [{match['type']}] {match['name']}")
if len(matches) > 20:
print(f" ... 还有 {len(matches) - 20} 个结果未显示")
else:
print("未找到匹配项")
# 运行文件管理器主循环
def run(self):
print("简易文件管理器")
print("命令列表:")
print(" ls [a] - 列出文件 (a显示隐藏文件)")
print(" cd <目录> - 切换目录")
print(" back - 返回上一级")
print(" mkdir <名称> - 创建目录")
print(" touch <名称> - 创建文件")
print(" rm <名称> - 删除项目")
print(" search <关键词> - 搜索文件")
print(" bookmark add <名称> [路径] - 添加书签")
print(" bookmark go <名称> - 跳转到书签")
print(" bookmark list - 显示书签")
print(" exit - 退出")
# 主命令循环
while True:
try:
# 显示当前目录提示符
command = input(f"\n{self.base_dir}> ").strip()
if not command:
continue
# 解析命令和参数
parts = command.split()
cmd = parts[0].lower()
args = parts[1:]
# 命令分发
if cmd == "ls":
show_hidden = len(args) > 0 and args[0] == "a"
files = self.get_current_files(show_hidden)
self.display_files(files)
elif cmd == "cd":
if args:
self.navigate(args[0])
else:
print("用法: cd <目录>")
elif cmd == "back":
if not self.go_back():
print("无法返回")
elif cmd == "mkdir":
if args:
self.create_dir(args[0])
else:
print("用法: mkdir <目录名>")
elif cmd == "touch":
if args:
self.create_file(args[0])
else:
print("用法: touch <文件名>")
elif cmd == "rm":
if args:
confirm = len(args) > 1 and args[1] == "-y"
self.delete_item(args[0], not confirm)
else:
print("用法: rm <名称> [-y]")
elif cmd == "search":
if args:
self.search_files(" ".join(args))
else:
print("用法: search <关键词>")
elif cmd == "bookmark":
# 书签子命令处理
if len(args) >= 2:
subcmd = args[0]
if subcmd == "add":
name = args[1]
path = args[2] if len(args) > 2 else None
self.add_bookmark(name, path)
elif subcmd == "go":
self.jump_to_bookmark(args[1])
else:
print("未知的书签子命令")
elif args and args[0] == "list":
self.show_bookmarks()
else:
print("书签命令用法:")
print(" bookmark add <名称> [路径]")
print(" bookmark go <名称>")
print(" bookmark list")
elif cmd in ["exit", "quit"]:
print("再见!")
break
else:
print(f"未知命令: {cmd}")
except KeyboardInterrupt:
print("\n\n再见!")
break
except Exception as e:
print(f"发生错误: {e}")
# 程序入口
if __name__ == "__main__":
# 创建文件管理器实例并运行
manager = SimpleFileManager()
manager.run()
其他
os.walk函数
os.walk()是 Python 文件系统操作中最常用、最强大的工具之一,几乎所有的文件遍历需求都可以用它解决。
os.walk(top, topdown=True, onerror=None, followlinks=False) 返回一个三元组{dirpath:字符串,当前正在遍历的目录路径,dirnames:列表,当前目录下的所有子目录,filenames:列表,当前目录下的所有非目录文件名}
pathlib模块
pathlib 是 Python 3.4+ 中用于处理文件路径的现代化模块,比传统的 os.path 更好用、更直观。
pathlib.Path 对象一个智能的路径对象,把文件/文件夹路径变成了可以操作的对象。
其中的is_dir() 方法用于检查 target 路径是否指向一个目录,unlink()方法用于删除 target 路径所指向的文件。
shutil模块
shutil是Python中用于高级文件操作的模块,提供了对文件和文件夹进行复制、移动、删除等操作的功能,比基本的os模块更强大。其rmtree方法常用于递归删除整个目录树,包括所有子目录和文件。它类似于命令行中的 rm -rf 命令。
shutil.rmtree(path, ignore_errors=False, onerror=None, dir_fd=None) 要谨慎使用,因为会删除整个目录树,且不可恢复