MinIO使用记录

news/2024/10/6 4:22:34/文章来源:https://www.cnblogs.com/ComfortableM/p/18286363

探索MinIO:高性能、分布式对象存储解决方案

注:本文除代码外多数为AI生成

最近因为有项目需要换成Amazon S3的云存储,所以把之前做过的minio部分做一个记录,后面也会把基于这版改造的S3方法发出来记录。

MinIO简介

MinIO是一款高性能、分布式对象存储服务器,设计用于在大规模环境中存储和检索非结构化数据集,如图像、视频和日志文件。它完全开源,遵循Apache License v2.0,并且与Amazon S3 API兼容,这使得从现有的S3环境迁移变得简单。MinIO支持多租户,确保了数据的安全性和隔离性,同时提供了多种数据持久性和一致性保障机制。由于其出色的性能特性,如高吞吐量和低延迟,MinIO成为了众多企业和组织在构建现代云基础设施时的首选对象存储解决方案。

MinIO架构与技术

去中心化架构
  • 无共享架构:MinIO采用了一种去中心化的无共享架构,这意味着没有单一的瓶颈点或中心化的元数据服务器。数据和元数据分布在集群内的所有节点上,提高了系统的整体性能和可靠性。
  • 统一命名空间:尽管数据分布在多个节点上,但MinIO对外提供了一个统一的命名空间,用户无需关心数据的具体位置。
分布式特性
  • 水平扩展:MinIO可以很容易地通过添加更多的节点来水平扩展,每个节点都是对等的,可以独立运行和存储数据。
  • 纠删编码:为了提高数据的可靠性和容错性,MinIO使用纠删编码技术(Erasure Coding)来存储数据。这允许数据在多个节点上以冗余的形式存在,即使部分节点发生故障,数据仍然可读。
高性能
  • 并发处理:MinIO的设计考虑到了高并发性,能够同时处理大量的读写请求,提供低延迟和高吞吐量。
  • 网络优化:MinIO通过高效的网络协议和数据传输优化,确保数据在网络中的快速流动。
兼容性
  • S3 API兼容:MinIO完全兼容Amazon S3 API,这使得它可以无缝地与许多已有的应用程序和服务集成,降低了迁移成本。
安全性
  • 加密:MinIO支持静态数据加密,确保数据在存储期间的安全。
  • 访问控制:通过IAM(Identity and Access Management)策略,MinIO提供了细粒度的访问控制,保护数据不被未授权访问。
开源与跨平台
  • 开源许可证:MinIO遵循Apache License v2.0开源协议,允许自由使用、修改和分发。
  • 跨平台:MinIO可以在多种操作系统上运行,包括Linux、Windows和macOS,增强了其部署灵活性。
集群部署
  • 多节点集群:MinIO可以部署为一个集群,其中包含多个节点,这些节点共同维护数据的一致性和可用性。
  • 负载均衡:在集群中,可以通过DNS轮询或负载均衡器来分配请求到不同的节点,确保负载均匀分布。
技术栈
  • Go语言:MinIO使用Go语言编写,这提供了良好的性能和简洁的代码基础。

Minio的安装部署

单节点部署

  • 参考https://www.cnblogs.com/ComfortableM/p/17384523.html

集群部署概念

  1. 节点:MinIO集群由多个节点组成,每个节点都是一个独立运行的MinIO服务器实例。
  2. 纠删编码:为了实现数据冗余和容错,MinIO使用纠删编码(Erasure Coding)。这种技术允许数据被分割成多个片段,并且每个片段都有额外的校验信息。如果集群中有节点失效,数据仍然可以从剩余的节点中重构出来。
  3. 数据分布:数据均匀分布在所有节点上,以达到负载均衡和最大化使用所有存储资源的目的。

部署步骤

  1. 环境准备
    • 确保有足够的物理服务器或虚拟机。
    • 准备好足够的磁盘空间,每台服务器可以使用单个磁盘或多个磁盘。
    • 配置网络,确保所有节点之间可以互相通信。
  2. 软件安装
    • 在每台服务器上安装MinIO软件。可以通过二进制包、Docker容器或软件包管理系统完成。
    • 配置MinIO服务器,指定数据存储目录和集群相关的配置。
  3. 启动MinIO服务
    • 在每个节点上启动MinIO服务,使用集群模式的启动参数。
    • 指定集群中的其他节点,以便它们可以相互发现并形成集群。
  4. 验证集群状态
    • 使用MinIO的管理命令或Web UI检查集群状态,确认所有节点是否已成功加入集群。
    • 测试读写操作,确保数据可以正确地在集群中分布和访问。
  5. 监控和维护
    • 设置监控,持续监控集群的健康状况和性能指标。
    • 定期进行维护,如数据平衡、硬件升级或替换故障节点。

关键考虑因素

  • 节点数量:集群至少需要4个节点来实现数据的冗余和分布。通常,节点数量越多,数据的可用性和性能就越好。
  • 数据冗余:根据纠删编码策略,集群可以容忍一定数量的节点故障而不会丢失数据。
  • 网络配置:确保网络稳定和高速,因为集群中的节点需要频繁地相互通信。
  • 故障恢复:设计故障恢复计划,包括节点替换、数据重建和灾难恢复策略。
  • 性能调优:根据实际工作负载,可能需要调整网络带宽、磁盘I/O或其他系统参数来优化性能。

扩展和缩放

  • 扩展:通过添加更多节点可以轻松扩展MinIO集群的容量和性能。
  • 缩放:移除节点时需要小心,确保数据冗余不会降低到不可接受的水平。

注意事项

  • 使用hosts文件或DNS服务来解决集群内部的域名或IP地址,避免直接在配置文件中硬编码IP地址,这有助于在节点变化时更容易地维护集群。
  • 在部署多节点多磁盘的集群时,确保遵循最佳实践,如避免在同一服务器上使用过多的磁盘,以防服务器故障导致大量数据不可用。

下面为例:

  • 节点启动方式,每个节点都需要启动
export MINIO_ACCESS_KEY=admin
export MINIO_SECRET_KEY=minioadmin
#console-address参数可设可不设
./minio server --address ":9001" --console-address ":9011" 
"http://ipA:9001/arcfile/minioData/data" 
"http://ipB:9001/arcfile/minioData/data"
"http://ipC:9001/arcfile/minioData/data"
"http://ipD:9001/arcfile/minioData/data" >/arcfile/minioData/logs/start.txt 2>&1 &
  • 如果要用来测试,可以一个服务器部署四个节点。以上面为例修改端口启动,或者参考下面的启动脚本
RUNNING_USER=root
MINIO_HOME=/opt/minio
MINIO_HOST=192.168.222.10
#accesskey and secretkey
ACCESS_KEY=admin 
SECRET_KEY=minioadminfor i in {01..04}; doSTART_CMD="MINIO_ACCESS_KEY=${ACCESS_KEY} MINIO_SECRET_KEY=${SECRET_KEY} nohup ${MINIO_HOME}/minio  server --address "${MINIO_HOST}:90${i}" http://${MINIO_HOST}:9001/opt/min-data1 http://${MINIO_HOST}:9002/opt/min-data2 http://${MINIO_HOST}:9003/opt/min-data3 http://${MINIO_HOST}:9004/opt/min-data4 > ${MINIO_HOME}/minio-90${i}.log 2>&1 &"su - ${RUNNING_USER} -c "${START_CMD}"
done

集成Spring boot项目

添加依赖
        <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.3.3</version></dependency><!--如果出现okhttp依赖冲突,添加下面依赖-->
<!--        <dependency>-->
<!--            <groupId>com.squareup.okhttp3</groupId>-->
<!--            <artifactId>okhttp</artifactId>-->
<!--            <version>4.9.0</version>-->
<!--        </dependency>-->
创建配置类
import io.minio.MinioClient;
import io.minio.errors.*;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Logger;@Configuration
public class MinioClientConfig {private final Logger log = Logger.getLogger(this.getClass().getName());@Value("${config.minio.url}")private String MINIO_URL;@Value("${config.minio.accessKey}")private String MINIO_ACCESS_KEY;@Value("${config.minio.secretKey}")private String MINIO_SECRET_KEY;@Beanpublic MinioClient getMinioClient() {if (MINIO_URL.length() == 0 || MINIO_URL == null) {throw new IllegalArgumentException("\n请正确配置Minio服务器的 URL 连接参数");}if (MINIO_ACCESS_KEY.length() == 0 || MINIO_ACCESS_KEY == null) {throw new IllegalArgumentException("\n请正确配置Minio服务器的 ACCESS_KEY 连接参数");}if (MINIO_SECRET_KEY.length() == 0 || MINIO_SECRET_KEY == null) {throw new IllegalArgumentException("\n请正确配置Minio服务器的 SECRET_KEY 连接参数");}MinioClient minioClient = MinioClient.builder().endpoint(MINIO_URL).credentials(MINIO_ACCESS_KEY, MINIO_SECRET_KEY).build();try {minioClient.listBuckets();} catch (ErrorResponseException e) {e.printStackTrace();throw new RuntimeException("\nMinio服务器连接异常\n请检查所配置的Minio连接信息Access-key和Secret-Key是否正确");} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();throw new RuntimeException("\nMinio服务器连接异常\n请检查Minio服务器是否已开启或所配置的Minio_url连接信息是否正确");} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}log.info("Minio服务器连接成功,URL = " + MINIO_URL);return minioClient;}
}

基本操作介绍

  • 创建桶
public boolean createBucket(String bucketName) throws RuntimeException {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
  • 配置桶权限为公开
public void BucketAccessPublic(String bucketName) {
String config = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucketMultipartUploads\",\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(config).build();
}
  • 上传对象

uploadObject()

//上传本地文件
public boolean uploadObject(String bucketName, String targetObject, String sourcePath) {try {minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(targetObject).filename(sourcePath).build());} catch (ErrorResponseException e) {e.printStackTrace();return false;} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}return true;}

putObject()

public boolean putObject(String bucketName, String object, InputStream inputStream) {try {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(object)//.contentType("application/pdf")不设置的话默认是"application/stream",这就是为什么某些文件上传上去无法直接预览的问题.stream(inputStream, -1, 10485760)//.tags(tags)上传可以直接携带标签.build());} catch (ErrorResponseException e) {e.printStackTrace();return false;} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}return true;}
  • 下载对象
    public GetObjectResponse getObject(String bucketName, String object) {GetObjectResponse object1 = null;//这个对象是集成了InputStream的FilterInputStream类,所以是可以直接用流来处理文件的try {object1 = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(object).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}return object1;}
  • 获取对象预签名Url
/*** 生成预签名URL,允许外部在限定时间内访问指定的MinIO对象。* * @param bucketName 存储桶名称* @param object 对象名称* @param expire 过期时间,单位是分钟* @param map 用于自定义HTTP响应头的映射,例如设置Content-Type* @return 返回预签名的URL,可以用于直接访问对象*/
public String presignedURLofObject(String bucketName, String object, int expire, Map<String, String> map) {// 设置响应的内容类型为application/jsonmap.put("response-content-type", "application/json");// 初始化预签名URL字符串String presignedObjectUrl = "";// 尝试获取预签名的URLtry {// 构建获取预签名URL的参数presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName)          // 设置存储桶名称.object(object)              // 设置对象名称.method(Method.GET)          // 设置HTTP方法为GET.expiry(expire, TimeUnit.MINUTES) // 设置过期时间为expire分钟后//.extraQueryParams(map)     // 注释掉的代码,用于设置额外的查询参数.build()                     // 构建参数对象);} catch (ErrorResponseException e) {// 处理错误响应异常e.printStackTrace();} catch (InsufficientDataException e) {// 数据不足异常e.printStackTrace();} catch (InternalException e) {// MinIO内部异常e.printStackTrace();} catch (InvalidKeyException e) {// 无效的访问密钥异常e.printStackTrace();} catch (InvalidResponseException e) {// 无效的响应异常e.printStackTrace();} catch (IOException e) {// 输入输出异常e.printStackTrace();} catch (NoSuchAlgorithmException e) {// 不存在算法异常e.printStackTrace();} catch (XmlParserException e) {// XML解析异常e.printStackTrace();} catch (ServerException e) {// 服务器异常e.printStackTrace();}// 返回预签名的URLreturn presignedObjectUrl;
}

部分方法集

MinioService

import io.minio.ComposeSource;
import io.minio.GetObjectResponse;
import io.minio.Result;
import io.minio.StatObjectResponse;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.stereotype.Service;import java.io.InputStream;
import java.util.List;
import java.util.Map;/*** MinioService接口,定义了与MinIO对象存储系统交互的方法集。*/
@Service
public interface MinioService {/*** 检查指定的存储桶是否存在。** @param bucketName 存储桶名称* @return 如果存储桶存在则返回true,否则返回false。*/boolean ifExistsBucket(String bucketName);/*** 创建一个新的存储桶。** @param bucketName 要创建的存储桶名称* @throws RuntimeException 如果创建失败抛出运行时异常* @return 如果创建成功则返回true,否则返回false。*/boolean createBucket(String bucketName) throws RuntimeException;/*** 删除指定的存储桶。** @param bucketName 要删除的存储桶名称* @return 如果删除成功则返回true,否则返回false。*/boolean removeBucket(String bucketName);/*** 列出所有已存在的存储桶。** @return 包含所有存储桶信息的列表。*/List<Bucket> alreadyExistBuckets();/*** 列出指定存储桶中的对象。** @param bucketName 要列出对象的存储桶名称* @param predir 可选前缀,用于过滤对象名* @param recursive 是否递归列出子目录的对象* @return 包含匹配条件的对象列表。*/List<Result<Item>> listObjects(String bucketName, String predir, boolean recursive);/*** 列出指定存储桶中的对象,用于组成对象操作。** @param bucketName 要列出对象的存储桶名称* @param predir 可选前缀,用于过滤对象名* @return 包含对象信息的List<ComposeSource>对象列表。*/List<ComposeSource> listObjects(String bucketName, String predir);/*** 复制一个对象到另一个位置。** @param pastBucket 原始存储桶名称* @param pastObject 原始对象名称* @param newBucket 目标存储桶名称* @param newObject 目标对象名称* @return 如果复制成功则返回true,否则返回false。*/boolean copyObject(String pastBucket, String pastObject, String newBucket, String newObject);/*** 下载存储桶中的对象到本地文件系统。** @param bucketName 存储桶名称* @param objectName 对象名称* @param targetPath 目标文件路径* @return 如果下载成功则返回true,否则返回false。*/boolean downObject(String bucketName, String objectName, String targetPath);/*** 生成一个预签名的URL,允许外部访问指定的对象。** @param bucketName 存储桶名称* @param object 对象名称* @param expire URL的有效期(分钟)* @return 预签名的URL。*/String presignedURLofObject(String bucketName, String object, int expire);/*** 生成一个预签名的URL,允许外部访问指定的对象,并自定义HTTP头部。** @param bucketName 存储桶名称* @param object 对象名称* @param expire URL的有效期(分钟)* @param map 自定义的HTTP头部信息* @return 预签名的URL。*/String presignedURLofObject(String bucketName, String object, int expire, Map<String, String> map);/*** 删除存储桶中的对象。** @param bucketName 存储桶名称* @param object 对象名称* @return 如果删除成功则返回true,否则返回false。*/boolean deleteObject(String bucketName, String object);/*** 上传本地文件到存储桶。** @param bucketName 存储桶名称* @param targetObject 目标对象名称* @param sourcePath 本地文件路径* @return 如果上传成功则返回true,否则返回false。*/boolean uploadObject(String bucketName, String targetObject, String sourcePath);/*** 从InputStream上传数据到存储桶。** @param bucketName 存储桶名称* @param object 对象名称* @param inputStream 数据流* @return 如果上传成功则返回true,否则返回false。*/boolean putObject(String bucketName, String object, InputStream inputStream);/*** 从InputStream上传数据到存储桶,并附带标签。** @param bucketName 存储桶名称* @param object 对象名称* @param inputStream 数据流* @param tags 对象的标签集合* @return 如果上传成功则返回true,否则返回false。*/boolean putObject(String bucketName, String object, InputStream inputStream, Map<String, String> tags);/*** 获取存储桶中的对象信息。** @param bucketName 存储桶名称* @param object 对象名称* @return 对象的响应信息。*/GetObjectResponse getObject(String bucketName, String object);/*** 检查存储桶中是否包含指定文件。** @param bucketName 存储桶名称* @param filename 文件名称* @param recursive 是否递归查找* @return 如果文件存在则返回true,否则返回false。*/boolean fileifexist(String bucketName, String filename, boolean recursive);/*** 获取对象的元数据标签。** @param bucketName 存储桶名称* @param object 对象名称* @return 对象的元数据标签集合。*/Map<String, String> getTags(String bucketName, String object);/*** 添加或更新对象的标签。** @param bucketName 存储桶名称* @param object 对象名称* @param addTags 要添加或更新的标签集合* @return 如果操作成功则返回true,否则返回false。*/boolean addTags(String bucketName, String object, Map<String, String> addTags);/*** 获取对象的状态信息。** @param bucketName 存储桶名称* @param object 对象名称* @return 对象的状态信息。*/StatObjectResponse statObject(String bucketName, String object);/*** 检查存储桶中对象是否存在。** @param bucketName 存储桶名称* @param objectName 对象名称* @return 如果对象存在则返回true,否则返回false。*/boolean ifExistObject(String bucketName, String objectName);/*** 从其他对象名中提取元名称。** @param objectName 对象名称* @return 提取的元名称。*/String getMetaNameFromOther(String objectName);/*** 更改对象的标签。** @param object 对象名称* @param tag 新的标签值* @return 如果更改成功则返回true,否则返回false。*/boolean changeTag(String object, String tag);/*** 设置存储桶的公共访问权限。** @param bucketName 存储桶名称*/void BucketAccessPublic(String bucketName);
}

MinioServiceImpl

import com.aspose.cad.internal.Y.S;
import com.xagxsj.erms.model.BucketName;
import com.xagxsj.erms.model.ObjectTags;
import com.xagxsj.erms.service.MinioService;
import com.xagxsj.erms.utils.FileUtil;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import io.minio.messages.Tags;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;import static com.xagxsj.erms.model.BucketName.METADATA;@Service
public class MinioServiceImpl implements MinioService {private final Logger log = Logger.getLogger(this.getClass().getName());@Qualifier("getMinioClient")@AutowiredMinioClient minioClient;/*** 检查指定的存储桶是否存在于MinIO服务器上。** @param bucketName 要检查的存储桶名称。* @return 如果存储桶存在,则返回true;否则返回false。*/@Overridepublic boolean ifExistsBucket(String bucketName) {boolean result = false;try {result = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());} catch (ErrorResponseException e) {e.printStackTrace();return false;} catch (InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return result;}/*** 在MinIO服务器上创建一个新的存储桶。** @param bucketName 要创建的存储桶名称。* @throws RuntimeException 如果尝试创建一个已存在的存储桶,则抛出此异常。* @return 如果存储桶创建成功,则返回true;否则返回false。*/@Overridepublic boolean createBucket(String bucketName) throws RuntimeException {if (ifExistsBucket(bucketName)) {throw new RuntimeException("桶已存在");}try {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return ifExistsBucket(bucketName);}/*** 从MinIO服务器上删除一个存储桶。** @param bucketName 要删除的存储桶名称。* @return 如果存储桶成功删除,则返回true;如果存储桶不存在,则返回true;否则返回false。*/@Overridepublic boolean removeBucket(String bucketName) {if (!ifExistsBucket(bucketName)) {return true;}try {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return !ifExistsBucket(bucketName);}/*** 列出MinIO服务器上所有存在的存储桶。** @return 返回一个包含所有存储桶信息的列表。*/@Overridepublic List<Bucket> alreadyExistBuckets() {List<Bucket> buckets = null;try {buckets = minioClient.listBuckets();} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return buckets;}/*** 检查指定的文件是否存在于存储桶中。** @param bucketName 存储桶名称。* @param filename 要检查的文件名。* @param recursive 是否递归搜索子目录。* @return 如果文件存在,则返回true;否则返回false。*/@Overridepublic boolean fileifexist(String bucketName, String filename, boolean recursive) {boolean flag = false;Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(filename).recursive(recursive).maxKeys(1000).build());for (Result<Item> result : results) {try {Item item = result.get();if (item.objectName().equals(filename)) {flag = true;break;}} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}}return flag;}/*** 列出存储桶中所有对象,可指定前缀和是否递归搜索子目录。** @param bucketName 存储桶名称。* @param predir 前缀过滤器。* @param recursive 是否递归搜索子目录。* @return 返回一个包含所有匹配对象的结果列表。*/@Overridepublic List<Result<Item>> listObjects(String bucketName, String predir, boolean recursive) {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(predir).recursive(recursive).maxKeys(1000).build());List<Result<Item>> list = new ArrayList<>();results.forEach(list::add);return list;}/*** 构建存储桶中对象的ComposeSource列表,用于复合对象操作。** @param bucketName 存储桶名称。* @param predir 前缀过滤器。* @return 返回一个包含所有匹配对象的ComposeSource列表。*/@Overridepublic List<ComposeSource> listObjects(String bucketName, String predir) {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(predir).recursive(true).maxKeys(1000).build());List<Result<Item>> list = new ArrayList<>();results.forEach(list::add);List<ComposeSource> sources = new ArrayList<>();for (Result<Item> itemResult : list) {try {sources.add(ComposeSource.builder().bucket(bucketName).object(itemResult.get().objectName()).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}}return sources;}/*** 复制一个对象到新的存储桶或新的对象名称。** @param pastBucket  原始存储桶名称* @param pastObject  原始对象名称* @param newBucket   新的存储桶名称* @param newObject   新的对象名称* @return 如果复制成功,则返回true;否则返回false。*/@Overridepublic boolean copyObject(String pastBucket, String pastObject, String newBucket, String newObject) {try {ObjectWriteResponse response = minioClient.copyObject(CopyObjectArgs.builder().bucket(newBucket).object(newObject).source(CopySource.builder().bucket(pastBucket).object(pastObject).build()).build());} catch (ErrorResponseException e) {e.printStackTrace();return false;} catch (InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return true;}/*** 下载存储桶中的对象到本地文件系统。** @param bucketName  存储桶名称* @param objectName  对象名称* @param targetPath  本地目标路径* @return 如果下载成功,则返回true;否则返回false。*/@Overridepublic boolean downObject(String bucketName, String objectName, String targetPath) {try {if ("".equals(objectName) || null == objectName) {throw new RuntimeException("检查电子文件FilePath是否为空,下载目标位置为:" + targetPath);}minioClient.downloadObject(DownloadObjectArgs.builder().bucket(bucketName).object(objectName).filename(targetPath)      //download local path.build());} catch (ErrorResponseException e) {e.printStackTrace();return false;} catch (InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return true;}/*** 获取存储桶中对象的预签名URL(GET方法)。** @param bucketName  存储桶名称* @param object      对象名称* @param expire      过期时间(分钟)* @return 预签名URL,如果发生错误则返回null。*/@Overridepublic String presignedURLofObject(String bucketName, String object, int expire) {String url = null;try {url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(object).expiry(expire, TimeUnit.MINUTES).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException | ServerException e) {e.printStackTrace();}return url;}/*** 获取存储桶中对象的预签名URL,允许设置额外的查询参数。** @param bucketName  存储桶名称* @param object      对象名称* @param expire      过期时间(分钟)* @param map         额外的查询参数* @return 预签名URL,如果发生错误则返回空字符串。*/@Overridepublic String presignedURLofObject(String bucketName, String object, int expire, Map<String, String> map) {map.put("response-content-type", "application/json");String presignedObjectUrl = "";try {presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(object).method(Method.GET).expiry(expire, TimeUnit.MINUTES).extraQueryParams(map).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException | ServerException e) {e.printStackTrace();}return presignedObjectUrl;}/*** 删除存储桶中的对象。** @param bucketName  存储桶名称* @param object      对象名称* @return 如果删除成功,则返回true;否则返回false。*/@Overridepublic boolean deleteObject(String bucketName, String object) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(object).build());} catch (ErrorResponseException e) {e.printStackTrace();return false;} catch (InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return true;}/*** 将本地文件上传至MinIO存储桶。** @param bucketName     存储桶名称* @param targetObject   目标对象名称* @param sourcePath     源文件路径* @return 如果上传成功,则返回true;否则返回false。*/@Overridepublic boolean uploadObject(String bucketName, String targetObject, String sourcePath) {try {minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(targetObject).filename(sourcePath).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();return false;}return true;}/*** 将输入流数据写入MinIO存储桶。** @param bucketName 存储桶名称* @param object     对象名称* @param inputStream 输入流* @return 如果写入成功,则返回true;否则返回false。*/@Overridepublic boolean putObject(String bucketName, String object, InputStream inputStream) {try {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(object).stream(inputStream, -1, 10485760).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();return false;}return true;}/*** 将带有标签的输入流数据写入MinIO存储桶。** @param bucketName 存储桶名称* @param object     对象名称* @param inputStream 输入流* @param tags       对象标签* @return 如果写入成功,则返回true;否则返回false。*/@Overridepublic boolean putObject(String bucketName, String object, InputStream inputStream, Map<String, String> tags) {try {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(object).stream(inputStream, -1, 10485760).tags(tags).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();return false;}return true;}/*** 从MinIO存储桶获取对象。** @param bucketName 存储桶名称* @param object     对象名称* @return 返回对象响应信息,如果发生错误则返回null。*/@Overridepublic GetObjectResponse getObject(String bucketName, String object) {GetObjectResponse object1 = null;try {object1 = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(object).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return object1;}/*** 获取对象的标签信息。** @param bucketName 存储桶名称* @param object     对象名称* @return 返回对象的标签映射,如果发生错误则返回null。*/@Overridepublic Map<String, String> getTags(String bucketName, String object) {Map<String, String> map = new HashMap<>();try {Tags objectTags = minioClient.getObjectTags(GetObjectTagsArgs.builder().bucket(bucketName).object(object).build());map = objectTags.get();} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();return null;}return map;}/*** 向对象添加或更新标签。** @param bucketName 存储桶名称* @param object     对象名称* @param addTags    要添加或更新的标签映射* @return 如果操作成功,则返回true;否则返回false。*/@Overridepublic boolean addTags(String bucketName, String object, Map<String, String> addTags) {Map<String, String> oldtags = new HashMap<>();Map<String, String> newTags = new HashMap<>();try {oldtags = getTags(bucketName, object);if (oldtags.size() > 0) {newTags.putAll(oldtags);}if (addTags != null && addTags.size() > 0) {newTags.putAll(addTags);}minioClient.setObjectTags(SetObjectTagsArgs.builder().bucket(bucketName).object(object).tags(newTags).build());return true;} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();return false;}}/*** 获取对象的状态信息。** @param bucketName 存储桶名称* @param object     对象名称* @return 返回对象状态信息,如果发生错误则返回null。*/@Overridepublic StatObjectResponse statObject(String bucketName, String object) {StatObjectResponse statObject = null;try {statObject =minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(object).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}return statObject;}/*** 判断存储桶中是否存在指定对象。** @param bucketName   存储桶名称* @param objectName   对象名称* @return 如果存在,则返回true;否则返回false。*/@Overridepublic boolean ifExistObject(String bucketName, String objectName) {return listObjects(bucketName, objectName, true).size() >= 1;}/*** 从元数据存储桶中获取与特定对象相关的元数据对象名。** @param objectName 原始对象名称* @return 返回编码后的元数据对象名,如果没有找到对应的元数据则返回其文件名。*/@Overridepublic String getMetaNameFromOther(String objectName) {String metaobject = "";List<Result<Item>> results = listObjects(BucketName.METADATA, FileUtil.getPreMeta(objectName), true);if (results.size() == 1) {try {metaobject = results.get(0).get().objectName();Map<String, String> tags = getTags(BucketName.METADATA, metaobject);String s = tags.get(ObjectTags.FILENAME);// 解码后再编码以确保正确处理特殊字符// URLDecoder.decode(s,"UTF-8");return URLEncoder.encode(s, "UTF-8");} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}}return FileUtil.getFileName(metaobject);}/*** 修改对象的标签信息。** @param object 对象名称* @param tag 新的标签值* @return 如果修改成功,则返回true;否则返回false。*/@Overridepublic boolean changeTag(String object, String tag) {try {Map<String, String> map = minioClient.getObjectTags(GetObjectTagsArgs.builder().bucket(BucketName.METADATA).object(object).build()).get();Map<String, String> map1 = new HashMap<>();tag = tag + FileUtil.getSuffix(object);map1.put(ObjectTags.FILENAME, tag);map1.put(ObjectTags.OPERATOR, map.get(ObjectTags.OPERATOR));minioClient.setObjectTags(SetObjectTagsArgs.builder().bucket(BucketName.METADATA).object(object).tags(map1).build());return true;} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();return false;}}/*** 设置存储桶的访问策略为公开访问。** @param bucketName 存储桶名称*/@Overridepublic void BucketAccessPublic(String bucketName) {String config = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucketMultipartUploads\",\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";try {minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(config).build());} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {e.printStackTrace();}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/738884.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝牙音箱App设计总结

前言 最近做了一个关于带Sound bar的智能电视的蓝牙项目,就是将电视Sound bar当作蓝牙音箱,将手机、电脑等设备的声音传输到电视,通过电视Soundbar播放声音。做这个项目的时候遇到了各种大大小小的问题,好在都解决了。本篇文章总结了在设计蓝牙相关的项目时需要了解的小知识…

设计模式学习(二)工厂模式——抽象工厂模式

介绍抽象工厂模式,并说明其优缺点目录背景抽象工厂模式优点与缺点 背景 现在我需要开发一个相机操作模块,它可能在Windows下运行,也可能在Linux下运行。由于在厂家提供的SDK中,Windows下的SDK和Linux下的SDK是有区别的,因此我们要创建两个类去封装这两个不同平台下的API。…

aippt 实现原理 AI生成PPT开源项目

AI生成PPT原理与代码实现通过 AI 生成 PPT 火了好长一段时间了,该类型产品也越来越多,我分析了几个主流的 aippt 产品,其中有一家公司的技术原理让我眼前一亮:文多多 AI 生成 PPT,官网: https://docmee.cn 该产品在 github 上有对应开源项目:https://github.com/veasion…

自定义流程表单开发优势体现在什么地方?

一起来了解自自定义流程表单开发的优势特点。提质、增效、降本,应该是很多职场办公需要实现的发展目标。那么,应用什么样的软件平台可以实现?低代码技术平台、自定义流程表单开发是目前流行于职场行业中的软件产品,可视化操作界面、够灵活、易维护等优势特点明显,在推进企…

Matlab马尔可夫链蒙特卡罗法(MCMC)估计随机波动率(SV,Stochastic Volatility) 模型|附代码数据

全文下载链接:http://tecdat.cn/?p=16708 最近我们被客户要求撰写关于随机波动率的研究报告,包括一些图形和统计输出。 波动率是一个重要的概念,在金融和交易中有许多应用。它是期权定价的基础。波动率还可以让您确定资产配置并计算投资组合的风险价值 (VaR) 甚至波动率本身…

2024.7.5 鲜花

菜就多练空白とカタルシス——TOGENASHI TOGEARI。震惊,K某He 强推竟然是这首歌,三天重复上百遍…… どれだけ手に入れても どれだけ自分のものにしてもしてもしても 追いつけないな 高望みしすぎなんて 腐ったような言葉 誰しも誰よりも優れて欲しくはないんだよ 理由はただ…

泛娱乐出海新风口,视频云技术需要怎样的融合创新?

泛娱乐的音视频技术随着出海在演进,交互和内容的技术是内核,也在融合。 泛娱乐的音视频技术随着出海在演进,交互和内容的技术是内核,也在融合。 面向出海,虽然娱乐社交这个行业由来已久,但近几年的商业模式发生了巨大变化,比如行业刚兴起时,大家要先把DAU做大之后再…

米尔瑞米派集聚5种操作系统,兼顾学习开发和项目产品需要的派

米尔电子发布的瑞萨第一款MPU生态板卡-瑞米派(Remi Pi),采用瑞萨RZ/G2L双核A55芯片,接口丰富,全面兼容树莓派的扩展模块。瑞米派支持五种系统,兼顾学习开发和项目产品需要。软件提供五种软件系统分别为:基于Yocto构建的两种系统,一种是支持通用功能的精简型系统,另一种…

echarts中Label标签与数据项颜色设置为同一种颜色

echarts5中默认标签颜色不会跟数据项颜色保持一致,而是全都是黑色。想要实现label颜色和它的数据项颜色一致,需要手动继承颜色,设置label{ color: inherit}即可解决label标签颜色与数据项颜色一致。 https://echarts.apache.org/examples/zh/editor.html?c=pie-simple 注意…

GaussDB AI新特性:gs_index_advise推荐索引

GaussDB的AI新特性,可以把SQL文本嵌套在函数中,数据库会返回一个创建合适索引的列gs_index_advise(text) 描述:针对单条查询语句推荐索引。 参数: SQL语句字符串 返回值类型: record 一、通常的SQL优化会通过参数调优的方式进行调整,例如如下参数set enable_fast_query_s…

Packing Python to exe(打包Python成EXE文件)

Python文件要执行需要Python环境,如果package成EXE文件则可以随意放在任意主机上去执行。package步骤如下: 1. 安装pythoninstaller (pip install pyinstaller) 2.安装auto-py-to-exe(有UI界面,很方便使用)(pip install auto-py-to-exe) 3.然后直接运行命令auto-py-to-e…

Sqlalchemy 连接SQL Server 登录失败

实验系统环境 Windows平台 Sqlalchemy 2.0.23 Python 3.10 SQL Server 2012 aioodbc 0.5.0 问题详情 sqlalchemy.exc.InterfaceError: (pyodbc.InterfaceError) (28000, [28000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]登录失败。该登录名来自不受信任的域,不…