102 lines
3.1 KiB
Python
102 lines
3.1 KiB
Python
"""
|
|
文件工具函数
|
|
提供统一的文件删除功能,自动处理缩略图同步删除
|
|
"""
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from app.config import get_settings
|
|
|
|
settings = get_settings()
|
|
|
|
# 文件系统路径(从配置读取)
|
|
UPLOAD_DIR = Path(settings.UPLOAD_DIR)
|
|
THUMBNAIL_DIR = UPLOAD_DIR / "thumbnails"
|
|
|
|
# URL 路径
|
|
STORAGE_URL = "/storage/admin/images"
|
|
THUMBNAIL_URL = f"{STORAGE_URL}/thumbnails"
|
|
|
|
|
|
def cleanup_file(file_path: str | Path) -> bool:
|
|
"""
|
|
删除文件并同步删除对应的缩略图
|
|
|
|
Args:
|
|
file_path: 文件路径(相对 /uploads 的路径、/storage/admin/images/ 格式或绝对路径)
|
|
|
|
Returns:
|
|
bool: 是否成功删除原文件
|
|
"""
|
|
if not file_path:
|
|
return False
|
|
|
|
# 统一处理为 Path 对象
|
|
if isinstance(file_path, str):
|
|
# 处理新的存储路径格式 /storage/admin/images/...
|
|
if file_path.startswith("/storage/admin/images/"):
|
|
# 提取相对路径部分
|
|
relative_path = file_path[len("/storage/admin/images/"):]
|
|
full_path = UPLOAD_DIR / relative_path
|
|
else:
|
|
# 移除开头的 / 并构建完整路径(兼容旧格式)
|
|
relative_path = file_path.lstrip("/")
|
|
full_path = UPLOAD_DIR / relative_path
|
|
else:
|
|
full_path = file_path
|
|
|
|
# 删除原文件
|
|
deleted = False
|
|
try:
|
|
if full_path.exists():
|
|
full_path.unlink()
|
|
deleted = True
|
|
print(f"[cleanup] 已删除文件: {full_path}")
|
|
except Exception as e:
|
|
print(f"[cleanup] 删除文件失败 {full_path}: {e}")
|
|
|
|
# 同步删除缩略图
|
|
# 缩略图与原图同名,但扩展名统一为 .jpg,存放在 /uploads/thumbnails/
|
|
try:
|
|
thumbnail_name = f"{full_path.stem}.jpg"
|
|
thumb_path = THUMBNAIL_DIR / thumbnail_name
|
|
if thumb_path.exists():
|
|
thumb_path.unlink()
|
|
print(f"[cleanup] 已删除缩略图: {thumb_path}")
|
|
except Exception as e:
|
|
print(f"[cleanup] 删除缩略图失败: {e}")
|
|
|
|
return deleted
|
|
|
|
|
|
def cleanup_file_by_path(relative_path: str) -> bool:
|
|
"""
|
|
根据相对路径删除文件及其缩略图
|
|
|
|
Args:
|
|
relative_path: 相对于 /uploads 的路径,如 "20250420_xxx.jpg"
|
|
或者完整的存储路径如 "/storage/admin/images/xxx.jpg"
|
|
|
|
Returns:
|
|
bool: 是否成功删除原文件
|
|
"""
|
|
if not relative_path:
|
|
return False
|
|
|
|
# 排除外部 URL
|
|
if relative_path.startswith(("http://", "https://")):
|
|
print(f"[cleanup] 跳过外部 URL: {relative_path}")
|
|
return False
|
|
|
|
# 处理新的存储路径格式 /storage/admin/images/...
|
|
if relative_path.startswith("/storage/admin/images/"):
|
|
# 提取相对路径部分
|
|
rel_path = relative_path[len("/storage/admin/images/"):]
|
|
full_path = UPLOAD_DIR / rel_path
|
|
else:
|
|
# 处理可能包含开头 / 的路径(兼容旧格式)
|
|
rel_path = relative_path.lstrip("/")
|
|
full_path = UPLOAD_DIR / rel_path
|
|
|
|
return cleanup_file(full_path)
|