ForcePilot/backend/package/yuxi/channel/utils/files.py
Kris 3b487fae57 feat(channel/utils): 新增工具模块与文件服务类
新增了通用工具包,包含文件操作工具、延迟加载工具类与函数,以及文件服务类,提供文件分类、安全命名与上传保存功能
2026-05-21 10:33:11 +08:00

79 lines
2.4 KiB
Python

from __future__ import annotations
import hashlib
import json
import logging
from pathlib import Path
from typing import Any
logger = logging.getLogger(__name__)
def read_json_file(file_path: str | Path) -> dict[str, Any]:
"""读取 JSON 文件并返回字典。"""
file_path = Path(file_path)
if not file_path.exists():
raise FileNotFoundError(f"File not found: {file_path}")
return json.loads(file_path.read_text(encoding="utf-8"))
def write_json_file(file_path: str | Path, data: dict[str, Any], *, indent: int = 2) -> None:
"""将字典写入 JSON 文件。"""
file_path = Path(file_path)
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(json.dumps(data, indent=indent, ensure_ascii=False), encoding="utf-8")
def compute_file_hash(file_path: str | Path, algorithm: str = "sha256") -> str:
"""计算文件的哈希值。"""
file_path = Path(file_path)
if not file_path.exists():
raise FileNotFoundError(f"File not found: {file_path}")
hasher = hashlib.new(algorithm)
hasher.update(file_path.read_bytes())
return hasher.hexdigest()
def ensure_directory(dir_path: str | Path) -> Path:
"""确保目录存在,如果不存在则创建。"""
path = Path(dir_path)
path.mkdir(parents=True, exist_ok=True)
return path
def safe_write_file(file_path: str | Path, content: str, *, encoding: str = "utf-8") -> None:
"""安全写入文件:先写入临时文件,再原子替换。"""
file_path = Path(file_path)
file_path.parent.mkdir(parents=True, exist_ok=True)
temp_path = file_path.with_suffix(f"{file_path.suffix}.tmp")
temp_path.write_text(content, encoding=encoding)
temp_path.replace(file_path)
def list_files(
directory: str | Path,
pattern: str = "*",
*,
recursive: bool = False,
) -> list[Path]:
"""列出目录中的文件。"""
directory = Path(directory)
if not directory.exists():
return []
if recursive:
return list(directory.rglob(pattern))
return list(directory.glob(pattern))
def delete_file(file_path: str | Path, *, missing_ok: bool = True) -> bool:
"""删除文件。"""
file_path = Path(file_path)
try:
file_path.unlink(missing_ok=missing_ok)
return True
except OSError:
logger.warning("Failed to delete file: %s", file_path)
return False