236 lines
7.1 KiB
Python
236 lines
7.1 KiB
Python
![]() |
"""
|
|||
|
文件管理器模块
|
|||
|
提供文件的读写、列表、删除等操作
|
|||
|
"""
|
|||
|
|
|||
|
import os
|
|||
|
import json
|
|||
|
import shutil
|
|||
|
from typing import List, Dict, Any
|
|||
|
from pathlib import Path
|
|||
|
|
|||
|
|
|||
|
class FileManager:
|
|||
|
"""
|
|||
|
文件管理器类
|
|||
|
|
|||
|
负责处理所有文件相关的操作,包括读写、列表、删除等
|
|||
|
"""
|
|||
|
|
|||
|
def __init__(self, base_path: str = None):
|
|||
|
"""
|
|||
|
初始化文件管理器
|
|||
|
|
|||
|
Args:
|
|||
|
base_path (str): 基础路径,默认为当前工作目录
|
|||
|
"""
|
|||
|
self.base_path = Path(base_path) if base_path else Path.cwd()
|
|||
|
self.workspace_path = self.base_path / 'workspace'
|
|||
|
|
|||
|
# 确保工作目录存在
|
|||
|
self.workspace_path.mkdir(exist_ok=True)
|
|||
|
|
|||
|
def list_files(self, path: str = '', include_hidden: bool = False) -> List[Dict[str, Any]]:
|
|||
|
"""
|
|||
|
列出指定路径下的文件和目录
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 相对路径,相对于工作目录
|
|||
|
include_hidden (bool): 是否包含隐藏文件
|
|||
|
|
|||
|
Returns:
|
|||
|
List[Dict[str, Any]]: 文件和目录信息列表
|
|||
|
"""
|
|||
|
target_path = self.workspace_path / path
|
|||
|
|
|||
|
if not target_path.exists():
|
|||
|
raise FileNotFoundError(f"Path does not exist: {path}")
|
|||
|
|
|||
|
if not target_path.is_dir():
|
|||
|
raise NotADirectoryError(f"Path is not a directory: {path}")
|
|||
|
|
|||
|
items = []
|
|||
|
|
|||
|
for item in sorted(target_path.iterdir()):
|
|||
|
if not include_hidden and item.name.startswith('.'):
|
|||
|
continue
|
|||
|
|
|||
|
stat = item.stat()
|
|||
|
items.append({
|
|||
|
'name': item.name,
|
|||
|
'path': str(item.relative_to(self.workspace_path)),
|
|||
|
'type': 'directory' if item.is_dir() else 'file',
|
|||
|
'size': stat.st_size if item.is_file() else 0,
|
|||
|
'modified': stat.st_mtime,
|
|||
|
'extension': item.suffix.lower() if item.is_file() else '',
|
|||
|
'is_markdown': item.suffix.lower() == '.md'
|
|||
|
})
|
|||
|
|
|||
|
return items
|
|||
|
|
|||
|
def read_file(self, path: str) -> str:
|
|||
|
"""
|
|||
|
读取文件内容
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 文件路径,相对于工作目录
|
|||
|
|
|||
|
Returns:
|
|||
|
str: 文件内容
|
|||
|
"""
|
|||
|
file_path = self.workspace_path / path
|
|||
|
|
|||
|
if not file_path.exists():
|
|||
|
raise FileNotFoundError(f"File not found: {path}")
|
|||
|
|
|||
|
if not file_path.is_file():
|
|||
|
raise IsADirectoryError(f"Path is a directory: {path}")
|
|||
|
|
|||
|
try:
|
|||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|||
|
return f.read()
|
|||
|
except UnicodeDecodeError:
|
|||
|
# 尝试其他编码
|
|||
|
with open(file_path, 'r', encoding='gbk') as f:
|
|||
|
return f.read()
|
|||
|
|
|||
|
def write_file(self, path: str, content: str, create_dirs: bool = True) -> None:
|
|||
|
"""
|
|||
|
写入文件内容
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 文件路径,相对于工作目录
|
|||
|
content (str): 文件内容
|
|||
|
create_dirs (bool): 是否自动创建目录
|
|||
|
"""
|
|||
|
file_path = self.workspace_path / path
|
|||
|
|
|||
|
if create_dirs:
|
|||
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|||
|
|
|||
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|||
|
f.write(content)
|
|||
|
|
|||
|
def delete_file(self, path: str) -> None:
|
|||
|
"""
|
|||
|
删除文件或目录
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 文件或目录路径,相对于工作目录
|
|||
|
"""
|
|||
|
target_path = self.workspace_path / path
|
|||
|
|
|||
|
if not target_path.exists():
|
|||
|
raise FileNotFoundError(f"Path does not exist: {path}")
|
|||
|
|
|||
|
if target_path.is_dir():
|
|||
|
shutil.rmtree(target_path)
|
|||
|
else:
|
|||
|
target_path.unlink()
|
|||
|
|
|||
|
def create_directory(self, path: str) -> None:
|
|||
|
"""
|
|||
|
创建目录
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 目录路径,相对于工作目录
|
|||
|
"""
|
|||
|
dir_path = self.workspace_path / path
|
|||
|
dir_path.mkdir(parents=True, exist_ok=True)
|
|||
|
|
|||
|
def file_exists(self, path: str) -> bool:
|
|||
|
"""
|
|||
|
检查文件是否存在
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 文件路径,相对于工作目录
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 文件是否存在
|
|||
|
"""
|
|||
|
return (self.workspace_path / path).exists()
|
|||
|
|
|||
|
def get_file_info(self, path: str) -> Dict[str, Any]:
|
|||
|
"""
|
|||
|
获取文件详细信息
|
|||
|
|
|||
|
Args:
|
|||
|
path (str): 文件路径,相对于工作目录
|
|||
|
|
|||
|
Returns:
|
|||
|
Dict[str, Any]: 文件详细信息
|
|||
|
"""
|
|||
|
file_path = self.workspace_path / path
|
|||
|
|
|||
|
if not file_path.exists():
|
|||
|
raise FileNotFoundError(f"File not found: {path}")
|
|||
|
|
|||
|
stat = file_path.stat()
|
|||
|
|
|||
|
return {
|
|||
|
'name': file_path.name,
|
|||
|
'path': str(file_path.relative_to(self.workspace_path)),
|
|||
|
'type': 'directory' if file_path.is_dir() else 'file',
|
|||
|
'size': stat.st_size,
|
|||
|
'modified': stat.st_mtime,
|
|||
|
'created': stat.st_ctime,
|
|||
|
'extension': file_path.suffix.lower(),
|
|||
|
'is_markdown': file_path.suffix.lower() == '.md'
|
|||
|
}
|
|||
|
|
|||
|
def search_files(self, pattern: str, path: str = '') -> List[str]:
|
|||
|
"""
|
|||
|
搜索文件
|
|||
|
|
|||
|
Args:
|
|||
|
pattern (str): 搜索模式(支持通配符)
|
|||
|
path (str): 搜索起始路径,相对于工作目录
|
|||
|
|
|||
|
Returns:
|
|||
|
List[str]: 匹配的文件路径列表
|
|||
|
"""
|
|||
|
target_path = self.workspace_path / path
|
|||
|
|
|||
|
if not target_path.exists():
|
|||
|
return []
|
|||
|
|
|||
|
matches = []
|
|||
|
for file_path in target_path.rglob(pattern):
|
|||
|
if file_path.is_file():
|
|||
|
matches.append(str(file_path.relative_to(self.workspace_path)))
|
|||
|
|
|||
|
return matches
|
|||
|
|
|||
|
def copy_file(self, src_path: str, dest_path: str) -> None:
|
|||
|
"""
|
|||
|
复制文件
|
|||
|
|
|||
|
Args:
|
|||
|
src_path (str): 源文件路径
|
|||
|
dest_path (str): 目标文件路径
|
|||
|
"""
|
|||
|
src = self.workspace_path / src_path
|
|||
|
dest = self.workspace_path / dest_path
|
|||
|
|
|||
|
if not src.exists():
|
|||
|
raise FileNotFoundError(f"Source file not found: {src_path}")
|
|||
|
|
|||
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|||
|
shutil.copy2(src, dest)
|
|||
|
|
|||
|
def move_file(self, src_path: str, dest_path: str) -> None:
|
|||
|
"""
|
|||
|
移动文件
|
|||
|
|
|||
|
Args:
|
|||
|
src_path (str): 源文件路径
|
|||
|
dest_path (str): 目标文件路径
|
|||
|
"""
|
|||
|
src = self.workspace_path / src_path
|
|||
|
dest = self.workspace_path / dest_path
|
|||
|
|
|||
|
if not src.exists():
|
|||
|
raise FileNotFoundError(f"Source file not found: {src_path}")
|
|||
|
|
|||
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|||
|
shutil.move(str(src), str(dest))
|