Files
mmkk/backend/utils/file_manager.py

236 lines
7.1 KiB
Python
Raw Normal View History

"""
文件管理器模块
提供文件的读写列表删除等操作
"""
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))