From e463094dc7fb2b4f3ce2c0972da5f774285dcea5 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 24 Aug 2025 09:21:55 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=95=B4=E7=90=86=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/modules/filemanager/storages/local.py | 127 +++++++++++++++------- 1 file changed, 85 insertions(+), 42 deletions(-) diff --git a/app/modules/filemanager/storages/local.py b/app/modules/filemanager/storages/local.py index 3f08056a..e49512e8 100644 --- a/app/modules/filemanager/storages/local.py +++ b/app/modules/filemanager/storages/local.py @@ -5,7 +5,7 @@ from typing import Optional, List from app import schemas from app.helper.directory import DirectoryHelper from app.log import logger -from app.modules.filemanager.storages import StorageBase +from app.modules.filemanager.storages import StorageBase, transfer_process from app.schemas.types import StorageSchema from app.utils.system import SystemUtils @@ -25,6 +25,9 @@ class LocalStorage(StorageBase): "softlink": "软链接" } + # 文件块大小,默认1MB + chunk_size = 1024 * 1024 + def init_storage(self): """ 初始化 @@ -191,21 +194,89 @@ class LocalStorage(StorageBase): """ return Path(fileitem.path) - def upload(self, fileitem: schemas.FileItem, path: Path, - new_name: Optional[str] = None) -> Optional[schemas.FileItem]: + def _copy_with_progress(self, src: Path, dest: Path): """ - 上传文件 - :param fileitem: 上传目录项 - :param path: 本地文件路径 - :param new_name: 上传后文件名 + 分块复制文件并回调进度 """ - dir_path = Path(fileitem.path) - target_path = dir_path / (new_name or path.name) - code, message = SystemUtils.move(path, target_path) - if code != 0: - logger.error(f"【local】移动文件失败:{message}") - return None - return self.get_item(target_path) + total_size = src.stat().st_size + copied_size = 0 + try: + progress_callback = transfer_process(src.as_posix()) + with open(src, "rb") as fsrc, open(dest, "wb") as fdst: + while True: + buf = fsrc.read(self.chunk_size) + if not buf: + break + fdst.write(buf) + copied_size += len(buf) + # 更新进度 + if progress_callback: + percent = copied_size / total_size * 100 + progress_callback(percent) + # 保留文件时间戳、权限等信息 + shutil.copystat(src, dest) + return True + except Exception as e: + logger.error(f"【local】复制文件 {src} 失败:{e}") + return False + + def upload( + self, + fileitem: schemas.FileItem, + path: Path, + new_name: Optional[str] = None + ) -> Optional[schemas.FileItem]: + """ + 上传文件(带进度) + """ + try: + dir_path = Path(fileitem.path) + target_path = dir_path / (new_name or path.name) + if self._copy_with_progress(path, target_path): + # 上传删除源文件 + path.unlink() + return self.get_item(target_path) + except Exception as err: + logger.error(f"【local】移动文件失败:{err}") + return None + + def copy( + self, + fileitem: schemas.FileItem, + path: Path, + new_name: str + ) -> bool: + """ + 复制文件(带进度) + """ + try: + src = Path(fileitem.path) + dest = path / new_name + if self._copy_with_progress(src, dest): + return True + except Exception as err: + logger.error(f"【local】复制文件失败:{err}") + return False + + def move( + self, + fileitem: schemas.FileItem, + path: Path, + new_name: str + ) -> bool: + """ + 移动文件(带进度) + """ + try: + src = Path(fileitem.path) + dest = path / new_name + if self._copy_with_progress(src, dest): + # 复制成功删除源文件 + src.unlink() + return True + except Exception as err: + logger.error(f"【local】移动文件失败:{err}") + return False def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool: """ @@ -229,34 +300,6 @@ class LocalStorage(StorageBase): return False return True - def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool: - """ - 复制文件 - :param fileitem: 文件项 - :param path: 目标目录 - :param new_name: 新文件名 - """ - file_path = Path(fileitem.path) - code, message = SystemUtils.copy(file_path, path / new_name) - if code != 0: - logger.error(f"【local】复制文件失败:{message}") - return False - return True - - def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool: - """ - 移动文件 - :param fileitem: 文件项 - :param path: 目标目录 - :param new_name: 新文件名 - """ - file_path = Path(fileitem.path) - code, message = SystemUtils.move(file_path, path / new_name) - if code != 0: - logger.error(f"【local】移动文件失败:{message}") - return False - return True - def usage(self) -> Optional[schemas.StorageUsage]: """ 存储使用情况