zyomnitools 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
zyomnitools/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import traceback
|
|
3
|
+
from typing import List, Tuple, Optional
|
|
4
|
+
from minio import Minio
|
|
5
|
+
from minio.error import S3Error
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MinioClient:
|
|
9
|
+
"""MinIO客户端封装类"""
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
endpoint: str,
|
|
13
|
+
access_key: str,
|
|
14
|
+
secret_key: str,
|
|
15
|
+
secure: bool = False,
|
|
16
|
+
region: Optional[str] = None
|
|
17
|
+
):
|
|
18
|
+
"""
|
|
19
|
+
初始化MinIO客户端
|
|
20
|
+
|
|
21
|
+
:param endpoint: MinIO服务地址(如 "localhost:9000")
|
|
22
|
+
:param access_key: 访问密钥(对应MINIO_ROOT_USER)
|
|
23
|
+
:param secret_key: 密钥(对应MINIO_ROOT_PASSWORD)
|
|
24
|
+
:param secure: 是否使用HTTPS,默认False(MinIO默认用HTTP)
|
|
25
|
+
:param region: 区域(可选,默认None)
|
|
26
|
+
"""
|
|
27
|
+
self.endpoint = endpoint
|
|
28
|
+
self.access_key = access_key
|
|
29
|
+
self.secret_key = secret_key
|
|
30
|
+
self.secure = secure
|
|
31
|
+
self.region = region
|
|
32
|
+
|
|
33
|
+
self.client = Minio(
|
|
34
|
+
endpoint=self.endpoint,
|
|
35
|
+
access_key=self.access_key,
|
|
36
|
+
secret_key=self.secret_key,
|
|
37
|
+
secure=self.secure,
|
|
38
|
+
region=self.region
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def _build_minio_path(self, cls_id: str, sub_path: str = "", prefix: str = "item") -> str:
|
|
42
|
+
"""
|
|
43
|
+
构建MinIO中的标准路径
|
|
44
|
+
|
|
45
|
+
:param cls_id: 分类ID
|
|
46
|
+
:param sub_path: 子路径(如 "output", "input")
|
|
47
|
+
:param prefix: 根目录前缀,默认"item"
|
|
48
|
+
:return: 完整的MinIO路径
|
|
49
|
+
"""
|
|
50
|
+
if cls_id is None:
|
|
51
|
+
return sub_path
|
|
52
|
+
|
|
53
|
+
# 构建路径: /item/{cls_id}/{sub_path}/
|
|
54
|
+
path_parts = [prefix, str(cls_id)]
|
|
55
|
+
if sub_path:
|
|
56
|
+
path_parts.append(sub_path)
|
|
57
|
+
|
|
58
|
+
# 确保路径以斜杠结尾(目录语义)
|
|
59
|
+
result = '/'.join(path_parts)
|
|
60
|
+
if not result.endswith('/'):
|
|
61
|
+
result += '/'
|
|
62
|
+
|
|
63
|
+
return result
|
|
64
|
+
|
|
65
|
+
def create_bucket(self, bucket_name: str) -> bool:
|
|
66
|
+
"""
|
|
67
|
+
创建存储桶(Bucket)
|
|
68
|
+
|
|
69
|
+
:param bucket_name: 存储桶名称
|
|
70
|
+
:return: 成功返回True,失败返回False
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
if not self.client.bucket_exists(bucket_name):
|
|
74
|
+
self.client.make_bucket(bucket_name)
|
|
75
|
+
print(f"存储桶 '{bucket_name}' 创建成功")
|
|
76
|
+
else:
|
|
77
|
+
print(f"存储桶 '{bucket_name}' 已存在")
|
|
78
|
+
return True
|
|
79
|
+
except S3Error as e:
|
|
80
|
+
print(f"创建存储桶失败: {e}")
|
|
81
|
+
return False
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f"创建存储桶时发生未知错误: {e}")
|
|
84
|
+
traceback.print_exc()
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
def upload_folder(
|
|
88
|
+
self,
|
|
89
|
+
local_dir: str,
|
|
90
|
+
cls_id: str,
|
|
91
|
+
bucket_name: str = "4dsimulator",
|
|
92
|
+
content_type: str = "application/octet-stream",
|
|
93
|
+
skip_hidden: bool = True
|
|
94
|
+
) -> bool:
|
|
95
|
+
"""
|
|
96
|
+
上传本地目录到MinIO指定存储桶,保持原目录结构
|
|
97
|
+
|
|
98
|
+
:param local_dir: 本地目录路径(绝对/相对路径均可)
|
|
99
|
+
:param cls_id: 分类ID,用于构建MinIO路径为 /item/{cls_id}/output/
|
|
100
|
+
:param bucket_name: 存储桶名称, 默认4dsimulator
|
|
101
|
+
:param content_type: 默认文件MIME类型,默认二进制流
|
|
102
|
+
:param skip_hidden: 是否跳过隐藏文件/目录(以.开头),默认True
|
|
103
|
+
:return: 全部文件上传成功返回True,否则返回False
|
|
104
|
+
"""
|
|
105
|
+
# 1. 校验本地目录是否存在
|
|
106
|
+
if not os.path.isdir(local_dir):
|
|
107
|
+
print(f"错误:本地目录 '{local_dir}' 不存在或不是有效目录")
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
# 2. 构建MinIO基础路径
|
|
111
|
+
minio_base_path = self._build_minio_path(cls_id, "output")
|
|
112
|
+
print(f"MinIO上传路径: {minio_base_path}")
|
|
113
|
+
|
|
114
|
+
# 3. 确保存储桶存在
|
|
115
|
+
if not self.client.bucket_exists(bucket_name):
|
|
116
|
+
print(f"存储桶 '{bucket_name}' 不存在,自动创建...")
|
|
117
|
+
if not self.create_bucket(bucket_name):
|
|
118
|
+
print("创建存储桶失败,终止目录上传")
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
# 4. 路径标准化处理
|
|
122
|
+
local_dir_abs = os.path.abspath(local_dir)
|
|
123
|
+
|
|
124
|
+
# 5. 遍历并上传所有文件
|
|
125
|
+
success_count = 0
|
|
126
|
+
fail_count = 0
|
|
127
|
+
failed_files = []
|
|
128
|
+
|
|
129
|
+
for root, dirs, files in os.walk(local_dir_abs):
|
|
130
|
+
# 跳过隐藏目录(如 .git、.idea)
|
|
131
|
+
if skip_hidden:
|
|
132
|
+
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
|
133
|
+
|
|
134
|
+
for file_name in files:
|
|
135
|
+
# 跳过隐藏文件(如 .DS_Store、.env)
|
|
136
|
+
if skip_hidden and file_name.startswith('.'):
|
|
137
|
+
continue
|
|
138
|
+
|
|
139
|
+
# 构建本地文件完整路径
|
|
140
|
+
local_file_path = os.path.join(root, file_name)
|
|
141
|
+
|
|
142
|
+
# 计算相对路径(相对于本地根目录)
|
|
143
|
+
relative_path = os.path.relpath(local_file_path, local_dir_abs)
|
|
144
|
+
relative_path = relative_path.replace(os.sep, '/')
|
|
145
|
+
|
|
146
|
+
# 构建MinIO中的对象名称(基础路径 + 相对路径)
|
|
147
|
+
object_name = minio_base_path + relative_path
|
|
148
|
+
|
|
149
|
+
# 上传单个文件
|
|
150
|
+
try:
|
|
151
|
+
self.client.fput_object(
|
|
152
|
+
bucket_name=bucket_name,
|
|
153
|
+
object_name=object_name,
|
|
154
|
+
file_path=local_file_path,
|
|
155
|
+
content_type=content_type
|
|
156
|
+
)
|
|
157
|
+
success_count += 1
|
|
158
|
+
except (FileNotFoundError, PermissionError, S3Error) as e:
|
|
159
|
+
print(f"✗ 上传失败: {local_file_path} -> {object_name}, 错误: {e}")
|
|
160
|
+
fail_count += 1
|
|
161
|
+
failed_files.append(local_file_path)
|
|
162
|
+
except Exception as e:
|
|
163
|
+
print(f"✗ 上传失败(未知错误): {local_file_path}, 错误: {e}")
|
|
164
|
+
fail_count += 1
|
|
165
|
+
failed_files.append(local_file_path)
|
|
166
|
+
|
|
167
|
+
# 6. 输出上传统计
|
|
168
|
+
total_count = success_count + fail_count
|
|
169
|
+
print(f"\n{'=' * 60}")
|
|
170
|
+
print(f"目录上传完成")
|
|
171
|
+
print(f"总计文件: {total_count} | 成功: {success_count} | 失败: {fail_count}")
|
|
172
|
+
if failed_files:
|
|
173
|
+
print(f"失败文件列表:")
|
|
174
|
+
for f in failed_files:
|
|
175
|
+
print(f" - {f}")
|
|
176
|
+
print(f"{'=' * 60}")
|
|
177
|
+
|
|
178
|
+
return fail_count == 0
|
|
179
|
+
|
|
180
|
+
def get_mesh(
|
|
181
|
+
self,
|
|
182
|
+
cls_id: str,
|
|
183
|
+
save_path: str,
|
|
184
|
+
bucket_name: str = "4dsimulator"
|
|
185
|
+
) -> bool:
|
|
186
|
+
"""
|
|
187
|
+
从MinIO下载指定分类ID的网格文件(PLY格式)
|
|
188
|
+
|
|
189
|
+
:param cls_id: 分类ID,用于构建MinIO路径为 /item/{cls_id}/realtime/{cls_id}_mesh.ply
|
|
190
|
+
:param save_path: 本地保存路径(包含文件名),如 "./meshes/mesh.ply"
|
|
191
|
+
:param bucket_name: 存储桶名称,默认为"4dsimulator"
|
|
192
|
+
:return: 下载成功返回True,失败返回False
|
|
193
|
+
"""
|
|
194
|
+
try:
|
|
195
|
+
# 1. 构建MinIO中的对象名称
|
|
196
|
+
# 路径格式: /item/{cls_id}/realtime/{cls_id}_mesh.ply
|
|
197
|
+
object_name = f"item/{cls_id}/realtime/{cls_id}_mesh.ply"
|
|
198
|
+
print(f"正在从MinIO下载网格文件: {object_name}")
|
|
199
|
+
|
|
200
|
+
# 2. 检查存储桶是否存在
|
|
201
|
+
if not self.client.bucket_exists(bucket_name):
|
|
202
|
+
print(f"错误:存储桶 '{bucket_name}' 不存在")
|
|
203
|
+
return False
|
|
204
|
+
|
|
205
|
+
# 3. 确保保存目录存在
|
|
206
|
+
save_path = os.path.join(save_path, f"{cls_id}_mesh.ply")
|
|
207
|
+
save_dir = os.path.dirname(save_path)
|
|
208
|
+
if save_dir and not os.path.exists(save_dir):
|
|
209
|
+
os.makedirs(save_dir, exist_ok=True)
|
|
210
|
+
print(f"创建本地目录: {save_dir}")
|
|
211
|
+
|
|
212
|
+
# 4. 下载文件
|
|
213
|
+
self.client.fget_object(
|
|
214
|
+
bucket_name=bucket_name,
|
|
215
|
+
object_name=object_name,
|
|
216
|
+
file_path=save_path
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# 5. 验证文件是否成功下载
|
|
220
|
+
if os.path.exists(save_path):
|
|
221
|
+
file_size = os.path.getsize(save_path)
|
|
222
|
+
print(f"✓ 网格文件下载成功: {object_name} -> {save_path}")
|
|
223
|
+
print(f" 文件大小: {file_size} 字节 ({file_size / 1024:.2f} KB)")
|
|
224
|
+
return True
|
|
225
|
+
else:
|
|
226
|
+
print(f"✗ 下载的文件不存在: {save_path}")
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
except S3Error as e:
|
|
230
|
+
print(f"✗ 下载网格文件失败(S3错误): {e}")
|
|
231
|
+
if e.code == 'NoSuchKey':
|
|
232
|
+
print(f" 提示:对象 '{object_name}' 在存储桶 '{bucket_name}' 中不存在")
|
|
233
|
+
return False
|
|
234
|
+
except Exception as e:
|
|
235
|
+
print(f"✗ 下载网格文件失败(未知错误): {e}")
|
|
236
|
+
traceback.print_exc()
|
|
237
|
+
return False
|
|
238
|
+
|
|
239
|
+
def download_output(
|
|
240
|
+
self,
|
|
241
|
+
local_dir: str,
|
|
242
|
+
cls_id: str,
|
|
243
|
+
bucket_name: str = "4dsimulator"
|
|
244
|
+
) -> bool:
|
|
245
|
+
"""
|
|
246
|
+
下载MinIO中指定分类ID下的所有文件到本地目录,保持路径结构
|
|
247
|
+
|
|
248
|
+
:param local_dir: 本地保存目录
|
|
249
|
+
:param cls_id: 分类ID,用于从 /item/{cls_id}/output/ 路径下载
|
|
250
|
+
:param bucket_name: 存储桶名称, 默认4dsimulator
|
|
251
|
+
:return: 成功返回True,失败返回False
|
|
252
|
+
"""
|
|
253
|
+
try:
|
|
254
|
+
# 1. 构建MinIO路径
|
|
255
|
+
minio_base_path = self._build_minio_path(cls_id, "output")
|
|
256
|
+
print(f"MinIO下载路径: {minio_base_path}")
|
|
257
|
+
|
|
258
|
+
# 2. 检查存储桶是否存在
|
|
259
|
+
if not self.client.bucket_exists(bucket_name):
|
|
260
|
+
print(f"错误:存储桶 '{bucket_name}' 不存在")
|
|
261
|
+
return False
|
|
262
|
+
|
|
263
|
+
# 3. 递归列举路径下的所有对象
|
|
264
|
+
objects = self.client.list_objects(
|
|
265
|
+
bucket_name=bucket_name,
|
|
266
|
+
prefix=minio_base_path,
|
|
267
|
+
recursive=True
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
# 4. 收集对象列表
|
|
271
|
+
object_list = list(objects)
|
|
272
|
+
if not object_list:
|
|
273
|
+
print(f"路径 '{minio_base_path}' 下没有找到任何对象")
|
|
274
|
+
return True
|
|
275
|
+
|
|
276
|
+
# 5. 确保本地目录存在
|
|
277
|
+
local_dir = os.path.join(local_dir, cls_id)
|
|
278
|
+
os.makedirs(local_dir, exist_ok=True)
|
|
279
|
+
|
|
280
|
+
# 6. 遍历所有对象并下载
|
|
281
|
+
success_count = 0
|
|
282
|
+
fail_count = 0
|
|
283
|
+
failed_objects = []
|
|
284
|
+
|
|
285
|
+
for obj in object_list:
|
|
286
|
+
# 跳过目录占位符(MinIO中目录以斜杠结尾,大小为0)
|
|
287
|
+
if obj.size == 0 and obj.object_name.endswith('/'):
|
|
288
|
+
print(f"跳过目录占位符: {obj.object_name}")
|
|
289
|
+
continue
|
|
290
|
+
|
|
291
|
+
# 计算相对路径(去掉MinIO基础路径)
|
|
292
|
+
relative_path = obj.object_name[len(minio_base_path):]
|
|
293
|
+
|
|
294
|
+
# 构建本地保存路径
|
|
295
|
+
local_file_path = os.path.join(local_dir, relative_path)
|
|
296
|
+
|
|
297
|
+
# 创建本地目录
|
|
298
|
+
local_file_dir = os.path.dirname(local_file_path)
|
|
299
|
+
if local_file_dir:
|
|
300
|
+
os.makedirs(local_file_dir, exist_ok=True)
|
|
301
|
+
|
|
302
|
+
# 下载单个对象
|
|
303
|
+
try:
|
|
304
|
+
self.client.fget_object(
|
|
305
|
+
bucket_name=bucket_name,
|
|
306
|
+
object_name=obj.object_name,
|
|
307
|
+
file_path=local_file_path
|
|
308
|
+
)
|
|
309
|
+
success_count += 1
|
|
310
|
+
except Exception as e:
|
|
311
|
+
print(f"✗ 下载失败: {obj.object_name}, 错误: {e}")
|
|
312
|
+
fail_count += 1
|
|
313
|
+
failed_objects.append(obj.object_name)
|
|
314
|
+
|
|
315
|
+
# 7. 输出下载统计
|
|
316
|
+
total_count = success_count + fail_count
|
|
317
|
+
print(f"\n{'=' * 60}")
|
|
318
|
+
print(f"目录下载完成")
|
|
319
|
+
print(f"总计对象: {total_count} | 成功: {success_count} | 失败: {fail_count}")
|
|
320
|
+
if failed_objects:
|
|
321
|
+
print(f"失败对象列表:")
|
|
322
|
+
for obj in failed_objects:
|
|
323
|
+
print(f" - {obj}")
|
|
324
|
+
print(f"{'=' * 60}")
|
|
325
|
+
|
|
326
|
+
return fail_count == 0
|
|
327
|
+
|
|
328
|
+
except S3Error as e:
|
|
329
|
+
print(f"下载目录失败(S3错误): {e}")
|
|
330
|
+
return False
|
|
331
|
+
except Exception as e:
|
|
332
|
+
print(f"下载目录失败(未知错误): {e}")
|
|
333
|
+
traceback.print_exc()
|
|
334
|
+
return False
|
|
335
|
+
|
|
336
|
+
def download_realtime(
|
|
337
|
+
self,
|
|
338
|
+
local_dir: str,
|
|
339
|
+
cls_id: str,
|
|
340
|
+
bucket_name: str = "4dsimulator",
|
|
341
|
+
folders: List[str] = None # 新增参数,允许自定义要下载的文件夹
|
|
342
|
+
) -> bool:
|
|
343
|
+
"""
|
|
344
|
+
下载MinIO中指定分类ID下的指定文件夹到本地目录,保持路径结构
|
|
345
|
+
|
|
346
|
+
:param local_dir: 本地保存目录
|
|
347
|
+
:param cls_id: 分类ID,用于从 /item/{cls_id}/realtime/ 路径下载
|
|
348
|
+
:param bucket_name: 存储桶名称, 默认4dsimulator
|
|
349
|
+
:param folders: 要下载的文件夹列表,默认为 ['masks', 'pose', 'rgb']
|
|
350
|
+
:return: 成功返回True,失败返回False
|
|
351
|
+
"""
|
|
352
|
+
try:
|
|
353
|
+
# 设置默认下载的文件夹
|
|
354
|
+
if folders is None:
|
|
355
|
+
folders = ['masks', 'pose', 'rgb']
|
|
356
|
+
|
|
357
|
+
# 1. 构建MinIO基础路径
|
|
358
|
+
minio_base_path = self._build_minio_path(cls_id, "realtime")
|
|
359
|
+
print(f"MinIO下载路径: {minio_base_path}")
|
|
360
|
+
print(f"要下载的文件夹: {', '.join(folders)}")
|
|
361
|
+
|
|
362
|
+
# 2. 检查存储桶是否存在
|
|
363
|
+
if not self.client.bucket_exists(bucket_name):
|
|
364
|
+
print(f"错误:存储桶 '{bucket_name}' 不存在")
|
|
365
|
+
return False
|
|
366
|
+
|
|
367
|
+
# 3. 确保本地目录存在
|
|
368
|
+
local_save_dir = os.path.join(local_dir, str(cls_id)) if cls_id else local_dir
|
|
369
|
+
os.makedirs(local_save_dir, exist_ok=True)
|
|
370
|
+
print(f"本地保存目录: {local_save_dir}")
|
|
371
|
+
|
|
372
|
+
# 4. 遍历目标文件夹
|
|
373
|
+
success_count = 0
|
|
374
|
+
fail_count = 0
|
|
375
|
+
failed_objects = []
|
|
376
|
+
|
|
377
|
+
for folder in folders:
|
|
378
|
+
folder_path = minio_base_path + folder + '/'
|
|
379
|
+
print(f"\n正在处理文件夹: {folder_path}")
|
|
380
|
+
|
|
381
|
+
# 列举该文件夹下的所有对象
|
|
382
|
+
try:
|
|
383
|
+
objects = self.client.list_objects(
|
|
384
|
+
bucket_name=bucket_name,
|
|
385
|
+
prefix=folder_path,
|
|
386
|
+
recursive=True
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
# 收集对象列表
|
|
390
|
+
object_list = list(objects)
|
|
391
|
+
if not object_list:
|
|
392
|
+
print(f" 警告:文件夹 '{folder_path}' 下没有找到任何对象")
|
|
393
|
+
continue
|
|
394
|
+
|
|
395
|
+
print(f" 找到 {len(object_list)} 个对象")
|
|
396
|
+
|
|
397
|
+
# 下载该文件夹下的所有对象
|
|
398
|
+
for obj in object_list:
|
|
399
|
+
# 跳过目录占位符
|
|
400
|
+
if obj.size == 0 and obj.object_name.endswith('/'):
|
|
401
|
+
continue
|
|
402
|
+
|
|
403
|
+
# 计算相对路径(去掉MinIO基础路径)
|
|
404
|
+
relative_path = obj.object_name[len(minio_base_path):]
|
|
405
|
+
|
|
406
|
+
# 构建本地保存路径
|
|
407
|
+
local_file_path = os.path.join(local_save_dir, relative_path)
|
|
408
|
+
|
|
409
|
+
# 创建本地目录
|
|
410
|
+
local_file_dir = os.path.dirname(local_file_path)
|
|
411
|
+
if local_file_dir:
|
|
412
|
+
os.makedirs(local_file_dir, exist_ok=True)
|
|
413
|
+
|
|
414
|
+
# 下载单个对象
|
|
415
|
+
try:
|
|
416
|
+
self.client.fget_object(
|
|
417
|
+
bucket_name=bucket_name,
|
|
418
|
+
object_name=obj.object_name,
|
|
419
|
+
file_path=local_file_path
|
|
420
|
+
)
|
|
421
|
+
success_count += 1
|
|
422
|
+
except Exception as e:
|
|
423
|
+
print(f" ✗ 下载失败: {obj.object_name}, 错误: {e}")
|
|
424
|
+
fail_count += 1
|
|
425
|
+
failed_objects.append(obj.object_name)
|
|
426
|
+
|
|
427
|
+
except S3Error as e:
|
|
428
|
+
print(f" 错误:无法访问文件夹 '{folder_path}': {e}")
|
|
429
|
+
continue
|
|
430
|
+
except Exception as e:
|
|
431
|
+
print(f" 错误:处理文件夹 '{folder_path}' 时发生异常: {e}")
|
|
432
|
+
continue
|
|
433
|
+
|
|
434
|
+
# 5. 输出下载统计
|
|
435
|
+
total_count = success_count + fail_count
|
|
436
|
+
print(f"\n{'=' * 60}")
|
|
437
|
+
print(f"Realtime数据下载完成")
|
|
438
|
+
print(f"目标文件夹: {', '.join(folders)}")
|
|
439
|
+
print(f"总计对象: {total_count} | 成功: {success_count} | 失败: {fail_count}")
|
|
440
|
+
if failed_objects:
|
|
441
|
+
print(f"失败对象列表:")
|
|
442
|
+
for obj in failed_objects:
|
|
443
|
+
print(f" - {obj}")
|
|
444
|
+
print(f"{'=' * 60}")
|
|
445
|
+
|
|
446
|
+
return fail_count == 0
|
|
447
|
+
|
|
448
|
+
except S3Error as e:
|
|
449
|
+
print(f"下载目录失败(S3错误): {e}")
|
|
450
|
+
return False
|
|
451
|
+
except Exception as e:
|
|
452
|
+
print(f"下载目录失败(未知错误): {e}")
|
|
453
|
+
traceback.print_exc()
|
|
454
|
+
return False
|
|
455
|
+
|
|
456
|
+
def delete_object(self, object_name: str, bucket_name: str = "4dsimulator") -> bool:
|
|
457
|
+
"""
|
|
458
|
+
删除MinIO中的对象
|
|
459
|
+
|
|
460
|
+
:param object_name: 要删除的对象名称
|
|
461
|
+
:param bucket_name: 存储桶名称, 默认4dsimulator
|
|
462
|
+
:return: 成功返回True,失败返回False
|
|
463
|
+
"""
|
|
464
|
+
try:
|
|
465
|
+
self.client.remove_object(bucket_name, object_name)
|
|
466
|
+
print(f"对象 '{object_name}' 已删除")
|
|
467
|
+
return True
|
|
468
|
+
except S3Error as e:
|
|
469
|
+
print(f"删除对象失败: {e}")
|
|
470
|
+
return False
|
|
471
|
+
except Exception as e:
|
|
472
|
+
print(f"删除对象时发生未知错误: {e}")
|
|
473
|
+
return False
|
|
474
|
+
|
|
475
|
+
def list_objects(
|
|
476
|
+
self,
|
|
477
|
+
prefix: str = "",
|
|
478
|
+
recursive: bool = False,
|
|
479
|
+
bucket_name: str = "4dsimulator"
|
|
480
|
+
) -> List[Tuple[str, int, str]]:
|
|
481
|
+
"""
|
|
482
|
+
列举存储桶中的对象
|
|
483
|
+
|
|
484
|
+
:param prefix: 前缀(用于过滤,如 "images/")
|
|
485
|
+
:param recursive: 是否递归列举子目录,默认False
|
|
486
|
+
:param bucket_name: 存储桶名称, 默认4dsimulator
|
|
487
|
+
:return: 对象列表,每个元素为 (对象名, 大小(字节), 最后修改时间)
|
|
488
|
+
"""
|
|
489
|
+
try:
|
|
490
|
+
objects = self.client.list_objects(
|
|
491
|
+
bucket_name=bucket_name,
|
|
492
|
+
prefix=prefix,
|
|
493
|
+
recursive=recursive
|
|
494
|
+
)
|
|
495
|
+
result = []
|
|
496
|
+
for obj in objects:
|
|
497
|
+
result.append((obj.object_name, obj.size, obj.last_modified))
|
|
498
|
+
|
|
499
|
+
print(f"存储桶 '{bucket_name}' 中找到 {len(result)} 个对象")
|
|
500
|
+
return result
|
|
501
|
+
except S3Error as e:
|
|
502
|
+
print(f"列举对象失败: {e}")
|
|
503
|
+
return []
|
|
504
|
+
except Exception as e:
|
|
505
|
+
print(f"列举对象时发生未知错误: {e}")
|
|
506
|
+
return []
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
if __name__ == "__main__":
|
|
510
|
+
# 初始化客户端
|
|
511
|
+
minio_client = MinioClient(
|
|
512
|
+
endpoint="192.168.112.162:39000",
|
|
513
|
+
access_key="admin",
|
|
514
|
+
secret_key="cogleapai",
|
|
515
|
+
secure=False
|
|
516
|
+
)
|
|
517
|
+
cls_id = "200"
|
|
518
|
+
print("MinIO客户端测试开始")
|
|
519
|
+
|
|
520
|
+
# 1. 上传文件夹
|
|
521
|
+
minio_client.upload_folder(
|
|
522
|
+
local_dir="./test_data",
|
|
523
|
+
cls_id=cls_id
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
# 2. 下载output目录
|
|
527
|
+
minio_client.download_output(
|
|
528
|
+
local_dir="./downloaded_output",
|
|
529
|
+
cls_id=cls_id
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
# 3. 下载realtime目录(masks, pose, rgb)
|
|
533
|
+
minio_client.download_realtime(
|
|
534
|
+
local_dir="./downloaded_realtime",
|
|
535
|
+
cls_id=cls_id
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
# 4. 下载mesh文件
|
|
539
|
+
minio_client.get_mesh(
|
|
540
|
+
cls_id=cls_id,
|
|
541
|
+
save_path="./meshes/"
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# 5. 列举文件
|
|
545
|
+
objects = minio_client.list_objects(
|
|
546
|
+
prefix=f"item/{cls_id}/output/",
|
|
547
|
+
recursive=True
|
|
548
|
+
)
|
|
549
|
+
print(f"共找到 {len(objects)} 个文件")
|
|
550
|
+
|
|
551
|
+
print("测试完成")
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
zyomnitools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
zyomnitools/minio_client.py,sha256=ttHv9aFkx0o8ybhnCMebBKgY25aNXqgPN6tTYTISO28,21097
|
|
3
|
+
zyomnitools-0.0.1.dist-info/METADATA,sha256=b0rx0xeUUYvJylJLoiz-5PBLUEQMl5L5V1w0JXmTSuQ,152
|
|
4
|
+
zyomnitools-0.0.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
5
|
+
zyomnitools-0.0.1.dist-info/top_level.txt,sha256=yAzxqg8YnvRdupF8wbRGBS7FRYBtUgIg8R6rLDT6fKk,12
|
|
6
|
+
zyomnitools-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zyomnitools
|