Loading... > ⚠️ **请注意**:本内容部分由 AI 生成,请读者自行判断其准确性与适用性。 ## 一、MinIO 概述 MinIO 是一个基于 Apache License v2.0 开源协议的企业级对象存储系统,采用 Go 语言实现。它专为云原生环境设计,可作为构建存储基础设施的高性能解决方案,支持单机、分布式、多租户等多种部署模式。 **核心特点**: - **S3 兼容**:完全兼容 Amazon S3 API,可无缝迁移 - **高性能**:在标准硬件上可达到 183 GB/s 读取和 171 GB/s 写入速度 - **云原生**:支持 Kubernetes 原生集成,提供 Helm Chart 和 Operator - **多重保护**:支持纠删码(Erasure Code)、位衰减保护(Bitrot Protection) - **多语言支持**:提供 Java、Python、Go、JavaScript 等主流语言 SDK --- ## 二、Java SDK 核心功能 ### 2.1 依赖配置 Maven 项目需引入 MinIO Java SDK 依赖: ```xml <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.5.10</version> </dependency> ``` ### 2.2 客户端初始化 所有操作的核心是 `MinioClient` 对象,通过 Builder 模式构建: ```java MinioClient minioClient = MinioClient.builder() .endpoint("http://localhost:9000") .credentials("accessKey", "secretKey") .build(); ``` --- ## 三、文件上传方式对比 根据搜索结果,Java SDK 支持多种上传方式: | 上传方式 | 适用场景 | 关键方法 | 特点 | | ----------------- | -------------------- | ---------------------------------- | ------------------------------------ | | **本地上传** | 文件已存储在本地磁盘 | `uploadObject()` | 直接指定文件路径,自动处理流 | | **流式上传** | 内存中的数据或网络流 | `putObject()` | 支持 InputStream,灵活但需手动管理流 | | **分片上传** | 大文件(>500MB) | `uploadPart()` + `composeObject()` | 断点续传,并发上传 | | **MultipartFile** | Web 应用文件上传 | 结合 Spring 封装 | 常用于 Controller 层接收文件 | --- ## 四、完整 Java 测试方法 以下提供一套完整的可运行的测试方案,包含多种上传方式实现: ### 4.1 配置文件 (application.yml) ```yaml minio: endpoint: http://localhost:9000 access-key: minioadmin secret-key: minioadmin bucket-name: test-bucket ``` ### 4.2 MinIO 工具类 ```java import io.minio.*; import io.minio.errors.*; import org.springframework.web.multipart.MultipartFile; import java.io.*; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.UUID; public class MinioUtil { private static String endpoint = "http://localhost:9000"; private static String accessKey = "minioadmin"; private static String secretKey = "minioadmin"; private static String bucketName = "test-bucket"; /** * 方式1:本地上传(推荐用于本地文件) */ public static String uploadLocalFile(String localFilePath) throws Exception { MinioClient client = getClient(); // 自动创建桶 ensureBucketExists(client); // 生成唯一文件名 String fileName = UUID.randomUUID() + localFilePath.substring(localFilePath.lastIndexOf(".")); client.uploadObject(UploadObjectArgs.builder() .bucket(bucketName) .object(fileName) .filename(localFilePath) .build()); return endpoint + "/" + bucketName + "/" + fileName; } /** * 方式2:流式上传(支持内存数据) */ public static String uploadStream(InputStream inputStream, String originalFileName) throws Exception { MinioClient client = getClient(); ensureBucketExists(client); String fileName = UUID.randomUUID() + originalFileName.substring(originalFileName.lastIndexOf(".")); client.putObject(PutObjectArgs.builder() .bucket(bucketName) .object(fileName) .stream(inputStream, inputStream.available(), -1) .build()); return endpoint + "/" + bucketName + "/" + fileName; } /** * 方式3:MultipartFile 上传(Web 应用) */ public static String uploadMultipartFile(MultipartFile file) throws Exception { return uploadStream(file.getInputStream(), file.getOriginalFilename()); } /** * 方式4:带完整性校验的上传 */ public static String uploadWithIntegrityCheck(String filePath) throws Exception { MinioClient client = getClient(); ensureBucketExists(client); // 计算本地文件MD5 String md5 = calculateMD5(filePath); String fileName = UUID.randomUUID() + filePath.substring(filePath.lastIndexOf(".")); File file = new File(filePath); Map<String, String> metadata = new HashMap<>(); metadata.put("md5", md5); client.putObject(PutObjectArgs.builder() .bucket(bucketName) .object(fileName) .stream(new FileInputStream(file), file.length(), -1) .userMetadata(metadata) .build()); // 验证上传完整性 if (checkFileIntegrity(client, filePath, bucketName, fileName)) { System.out.println("文件上传成功且完整:" + fileName); return endpoint + "/" + bucketName + "/" + fileName; } else { throw new RuntimeException("文件完整性校验失败"); } } // 辅助方法 private static MinioClient getClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } private static void ensureBucketExists(MinioClient client) throws Exception { if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); } } private static String calculateMD5(String filePath) throws Exception { try (FileInputStream fis = new FileInputStream(filePath)) { return DigestUtils.md5Hex(fis); } } private static boolean checkFileIntegrity(MinioClient client, String localPath, String bucket, String object) throws Exception { String localMD5 = calculateMD5(localPath); StatObjectResponse stat = client.statObject( StatObjectArgs.builder().bucket(bucket).object(object).build()); String minioMD5 = stat.userMetadata().get("md5"); return localMD5.equals(minioMD5); } } ``` ### 4.3 JUnit 测试类 ```java import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import java.io.FileInputStream; import java.io.File; @SpringBootTest public class MinioUploadTest { @Test public void testLocalUpload() { try { String filePath = "/path/to/test-file.pdf"; String url = MinioUtil.uploadLocalFile(filePath); System.out.println("上传成功,访问地址:" + url); } catch (Exception e) { e.printStackTrace(); } } @Test public void testStreamUpload() { try { String filePath = "/path/to/test-image.jpg"; FileInputStream fis = new FileInputStream(filePath); String url = MinioUtil.uploadStream(fis, "test-image.jpg"); System.out.println("流式上传成功:" + url); fis.close(); } catch (Exception e) { e.printStackTrace(); } } @Test public void testUploadWithCheck() { try { String filePath = "/path/to/large-file.zip"; String url = MinioUtil.uploadWithIntegrityCheck(filePath); System.out.println("完整性校验上传成功:" + url); } catch (Exception e) { e.printStackTrace(); } } @Test public void testBucketOperations() throws Exception { // 桶管理测试 MinioClient client = MinioClient.builder() .endpoint("http://localhost:9000") .credentials("minioadmin", "minioadmin") .build(); // 创建桶 String bucketName = "java-test-bucket"; if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); System.out.println("桶创建成功:" + bucketName); } // 列出所有桶 System.out.println("所有桶列表:"); client.listBuckets().forEach(bucket -> System.out.println("- " + bucket.name()) ); } } ``` --- ## 五、关键注意事项 1. **桶名称规范**:桶名必须全局唯一,遵循 DNS 命名规则(小写字母、数字、连字符) 2. **文件大小限制**:单个文件最大支持 5TB,但建议大文件使用分片上传 3. **性能优化**: - 小文件(<5MB)直接使用 `putObject` - 大文件使用分片上传,分片大小建议 16MB-64MB 4. **安全性**:生产环境务必启用 HTTPS 和访问策略控制 5. **异常处理**:需捕获 `MinioException`、`InvalidKeyException`、`NoSuchAlgorithmException` 等异常 --- ## 六、与 MinIO 相关的产品对比 - **MinIO**:如上所述,企业级对象存储 - **MongoDB GridFS**:MongoDB 的文件存储方案 - **FastDFS**:轻量级分布式文件系统 最后修改:2025 年 12 月 01 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏