# -*- coding: utf-8 -*- # @version : 1.0 # @Create Time : 2021/12/5 8:45 # @File : file_manage.py # @IDE : PyCharm # @desc : 保存图片到本地 import asyncio import io import os import zipfile from application.settings import STATIC_ROOT, BASE_DIR, STATIC_URL from fastapi import UploadFile import sys from core.exception import CustomException from utils.file.file_base import FileBase from aiopathlib import AsyncPath import aioshutil class FileManage(FileBase): """ 上传文件管理 """ def __init__(self, file: UploadFile, path: str): self.path = self.generate_static_file_path(path, file.filename) self.file = file async def save_image_local(self, accept: list = None) -> dict: """ 保存图片文件到本地 :param accept: :return: """ if accept is None: accept = self.IMAGE_ACCEPT await self.validate_file(self.file, max_size=5, mime_types=accept) return await self.async_save_local() async def save_audio_local(self, accept: list = None) -> dict: """ 保存音频文件到本地 :param accept: :return: """ if accept is None: accept = self.AUDIO_ACCEPT await self.validate_file(self.file, max_size=50, mime_types=accept) return await self.async_save_local() async def save_video_local(self, accept: list = None) -> dict: """ 保存视频文件到本地 :param accept: :return: """ if accept is None: accept = self.VIDEO_ACCEPT await self.validate_file(self.file, max_size=100, mime_types=accept) return await self.async_save_local() async def async_save_local(self) -> dict: """ 保存文件到本地 :return: 示例: { 'local_path': 'D:\\business\\kinit_dev\\aicheckv2-api\\static\\system\\20240301\\1709303205HuYB3mrC.png', 'remote_path': '/media/system/20240301/1709303205HuYB3mrC.png' } """ path = AsyncPath(self.path) if sys.platform == "win32": path = AsyncPath(self.path.replace("/", "\\")) if not await path.parent.exists(): await path.parent.mkdir(parents=True, exist_ok=True) await path.write_bytes(await self.file.read()) return { "local_path": str(path), "remote_path": STATIC_URL + str(path).replace(STATIC_ROOT, '').replace("\\", '/') } @classmethod async def async_save_temp_file(cls, file: UploadFile) -> str: """ 保存临时文件 :param file: :return: """ temp_file_path = await cls.async_generate_temp_file_path(file.filename) await AsyncPath(temp_file_path).write_bytes(await file.read()) return temp_file_path @classmethod async def unzip(cls, file: UploadFile, dir_path: str) -> str: """ 解压 zip 压缩包 :param file: :param dir_path: 解压路径 :return: """ if file.content_type != "application/x-zip-compressed": raise CustomException("上传文件类型错误,必须是 zip 压缩包格式!") # 读取上传的文件内容 contents = await file.read() # 将文件内容转换为字节流 zip_stream = io.BytesIO(contents) # 使用zipfile库解压字节流 with zipfile.ZipFile(zip_stream, "r") as zip_ref: zip_ref.extractall(dir_path) return dir_path @staticmethod async def async_copy_file(src: str, dst: str) -> None: """ 异步复制文件 根目录为项目根目录,传过来的文件路径均为相对路径 :param src: 原始文件 :param dst: 目标路径。绝对路径 """ if src[0] == "/": src = src.lstrip("/") src = AsyncPath(BASE_DIR) / src if not await src.exists(): raise CustomException(f"{src} 源文件不存在!") dst = AsyncPath(dst) if not await dst.parent.exists(): await dst.parent.mkdir(parents=True, exist_ok=True) await aioshutil.copyfile(src, dst) @staticmethod async def async_copy_dir(src: str, dst: str, dirs_exist_ok: bool = True) -> None: """ 复制目录 :param src: 源目录 :param dst: 目标目录 :param dirs_exist_ok: 是否覆盖 """ if not os.path.exists(dst): raise CustomException("目标目录不存在!") await aioshutil.copytree(src, dst, dirs_exist_ok=dirs_exist_ok)