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