minio_service.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. from minio import Minio
  2. from minio.error import S3Error
  3. from datetime import timedelta
  4. from app.providers.minio_client_provider import minio_client_provider
  5. from app.utils.logger_utils import logger
  6. class MinioService:
  7. def __init__(self):
  8. """初始化服务,不再创建固定的客户端"""
  9. pass
  10. def _ensure_bucket_exists(self, client: Minio, bucket_name: str):
  11. """确保桶存在"""
  12. if not client.bucket_exists(bucket_name):
  13. client.make_bucket(bucket_name)
  14. def list_files(self, prefix: str):
  15. """列出文件"""
  16. # 清理前缀
  17. if prefix == "/":
  18. prefix = ""
  19. elif prefix.startswith("/"):
  20. prefix = prefix[1:]
  21. if prefix and not prefix.endswith("/"):
  22. prefix += "/"
  23. try:
  24. objects = minio_client_provider.list_objects(prefix=prefix, recursive=False)
  25. results = []
  26. for obj in objects:
  27. # 跳过与前缀完全相同的对象(通常是文件夹标记)
  28. if obj.object_name == prefix:
  29. continue
  30. is_dir = obj.is_dir
  31. # 获取显示名称
  32. if is_dir:
  33. # 对于目录,去掉末尾的斜杠
  34. name = obj.object_name[len(prefix):].rstrip('/')
  35. else:
  36. name = obj.object_name[len(prefix):]
  37. # 跳过空名称
  38. if not name:
  39. continue
  40. results.append({
  41. "name": name,
  42. "path": obj.object_name,
  43. "is_dir": is_dir,
  44. "size": obj.size if not is_dir else 0,
  45. "last_modified": str(obj.last_modified) if not is_dir else None,
  46. "content_type": obj.content_type
  47. })
  48. # 排序
  49. results.sort(key=lambda x: (not x['is_dir'], x['name'].lower()))
  50. return results
  51. except S3Error as e:
  52. logger.error(f"列出文件错误: {e}", exc_info=True)
  53. raise e
  54. def upload_file(self, file_obj, file_path: str, content_type: str, file_size: int):
  55. """上传文件"""
  56. minio_client_provider.put_object(
  57. path=file_path,
  58. data=file_obj,
  59. length=file_size,
  60. content_type=content_type
  61. )
  62. def create_folder(self, folder_path: str):
  63. """创建文件夹"""
  64. if not folder_path.endswith("/"):
  65. folder_path += "/"
  66. # 创建一个空的 Object 以模拟文件夹
  67. minio_client_provider.put_empty_object(folder_path)
  68. def get_file_stream(self, file_path: str):
  69. """获取文件流"""
  70. return minio_client_provider.get_object(file_path)
  71. def delete_file(self, path: str, is_dir: bool):
  72. """删除文件或文件夹"""
  73. if is_dir:
  74. minio_client_provider.remove_objects_with_prefix(prefix=path)
  75. else:
  76. minio_client_provider.remove_object(path)
  77. def get_presigned_url(self, path: str):
  78. """获取预签名URL"""
  79. return minio_client_provider.get_presigned_url(path, expires=timedelta(hours=1))
  80. def get_storage_info(self):
  81. """获取存储桶使用情况"""
  82. return minio_client_provider.get_storage_info()
  83. # 实例化单例
  84. minio_service = MinioService()