Java 中间件:MinIO 文件上传(分片上传 + 预签名 URL)

Java 中间件:MinIO 文件上传(分片上传 + 预签名 URL)
在这里插入图片描述
👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Java中间件这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!

文章目录

Java 中间件:MinIO 文件上传(分片上传 + 预签名 URL)

在现代分布式系统和云原生架构中,文件存储与管理已成为一个核心基础设施需求。无论是用户头像、文档资料,还是视频、日志等大文件,都需要一个高效、安全、可扩展的存储方案。而对象存储服务(Object Storage Service)因其高可用性、弹性伸缩和低成本等优势,逐渐成为首选。

MinIO 是一个高性能、开源的对象存储系统,兼容 Amazon S3 API,非常适合私有化部署或混合云环境。它不仅支持标准的 PUT/GET 操作,还提供了强大的分片上传(Multipart Upload)机制和预签名 URL(Presigned URL)功能,使得前端直传、大文件处理和临时授权访问变得轻而易举。

本文将深入探讨如何在 Java 后端中间件中集成 MinIO,重点实现 分片上传预签名 URL 的完整流程,并结合实际代码示例、架构图和最佳实践,帮助开发者构建高效、安全的文件上传系统。🎯


为什么选择 MinIO?

MinIO 之所以在企业级应用中广受欢迎,主要有以下几个原因:

  • S3 兼容性:完全兼容 AWS S3 API,这意味着你可以无缝迁移现有 S3 应用到 MinIO,或在本地开发时使用 MinIO 作为替代。
  • 🚀 高性能:基于 Go 语言编写,单节点吞吐量可达数千 MB/s,集群模式下性能线性扩展。
  • 🔒 安全性:支持 TLS 加密、IAM 策略、桶策略、访问控制列表(ACL)等安全机制。
  • 📦 轻量易部署:单个二进制文件即可运行,无需依赖数据库或复杂配置。
  • 🌐 活跃社区:拥有庞大的开发者社区和丰富的 SDK 支持(包括 Java、Python、Go 等)。

官方文档地址:https://min.io/docs/minio/linux/index.html


分片上传 vs 普通上传

在讨论实现之前,我们需要理解两种上传方式的本质区别。

普通上传(Simple Upload)

适用于小文件(通常 < 100MB)。客户端直接将整个文件通过一次 HTTP PUT 请求发送到 MinIO。简单直接,但存在以下问题:

  • ❌ 大文件上传容易因网络波动失败,需重传整个文件。
  • ❌ 无法并行上传,速度受限。
  • ❌ 内存占用高,尤其在服务端中转时。

分片上传(Multipart Upload)

专为大文件设计(>100MB 或 GB 级别)。其核心思想是将文件切分为多个“分片”(Part),每个分片独立上传,最后由服务端合并。

优势显著:

  • 容错性强:某个分片失败只需重传该分片。
  • 并行加速:多个分片可同时上传,提升吞吐。
  • 断点续传:记录已上传分片,支持从中断处继续。
  • 内存友好:每次只处理一个小块。

MinIO 完全支持 S3 的 Multipart Upload 协议,Java SDK 提供了完善的封装。


预签名 URL:安全的前端直传机制

在传统架构中,文件上传往往经过后端服务器中转:前端 → 后端 → MinIO。这种方式虽然可控,但带来两个问题:

  1. 带宽压力:所有文件流量都经过后端,增加服务器负载。
  2. 延迟增加:多一跳网络传输。

预签名 URL(Presigned URL) 解决了这个问题。它允许后端生成一个带有临时授权的 URL,前端可直接将文件上传到 MinIO,绕过后端数据通道。

工作原理如下:

  1. 前端请求后端:“我要上传一个文件”。
  2. 后端验证权限后,调用 MinIO SDK 生成一个带签名的临时 URL(有效期可设,如 5 分钟)。
  3. 后端将该 URL 返回给前端。
  4. 前端使用该 URL 直接 PUT 文件到 MinIO。
  5. 上传完成后,前端通知后端“文件已就绪”,后端进行后续业务处理(如记录元数据)。

这种方式既保证了安全性(URL 有时效、可限制操作类型),又提升了性能。

AWS 官方对预签名 URL 的说明可参考:https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html


整体架构设计

为了兼顾大文件支持与安全性,我们采用 分片上传 + 预签名 URL 的组合方案。整体流程如下:

MinIO 存储Java 后端前端 (浏览器/APP)MinIO 存储Java 后端前端 (浏览器/APP)loop[对每个分片]1. 初始化上传请求 (文件名、大小)2. 创建分片上传任务 (CreateMultipartUpload)3. 返回 UploadId4. 返回 UploadId5. 请求第 N 个分片的预签名 URL6. 生成第 N 个分片的预签名 URL7. 返回预签名 URL8. 返回预签名 URL9. 直接上传分片 (PUT 到预签名 URL)10. 返回分片 ETag11. 上报分片 ETag 和序号12. 通知所有分片上传完成13. 调用 CompleteMultipartUpload14. 返回最终对象 URL15. 返回文件访问地址

该架构实现了:

  • 前端直传:减少后端带宽压力。
  • 分片容错:支持断点续传。
  • 权限控制:所有关键操作由后端发起,前端仅持有临时凭证。
  • 状态同步:后端掌握完整上传状态,便于后续业务处理。

环境准备

1. 启动 MinIO 服务

你可以通过 Docker 快速启动 MinIO:

docker run -p 9000:9000 -p 9001:9001 \ -e "MINIO_ROOT_USER=minioadmin"\ -e "MINIO_ROOT_PASSWORD=minioadmin"\ minio/minio server /data --console-address ":9001"
  • 9000:API 端口(S3 兼容接口)
  • 9001:Web 控制台端口

访问 http://localhost:9001 可进入管理界面。

2. 创建 Bucket

登录控制台,创建一个名为 file-upload-bucket 的存储桶(Bucket),并设置为私有(Private)。

3. Java 项目依赖

使用 Spring Boot 作为基础框架,添加 MinIO Java SDK:

<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.7</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
注意:MinIO Java SDK 版本建议使用 8.x 以上,以获得完整的分片上传支持。

核心代码实现

我们将构建一个 FileUploadService,封装 MinIO 的分片上传逻辑。

1. MinIO 客户端配置

首先,定义 MinIO 客户端 Bean:

@ConfigurationpublicclassMinioConfig{@Value("${minio.endpoint}")privateString endpoint;@Value("${minio.access-key}")privateString accessKey;@Value("${minio.secret-key}")privateString secretKey;@BeanpublicMinioClientminioClient(){returnMinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}}

application.yml 配置:

minio:endpoint: http://localhost:9000access-key: minioadmin secret-key: minioadmin 

2. 初始化分片上传

当用户开始上传一个大文件时,前端先调用 /initiate 接口,后端创建分片上传任务:

@RestController@RequestMapping("/api/upload")@RequiredArgsConstructorpublicclassFileUploadController{privatefinalFileUploadService fileUploadService;@PostMapping("/initiate")publicResponseEntity<InitiateResponse>initiateUpload(@RequestBodyInitiateRequest request){String uploadId = fileUploadService.initiateMultipartUpload(request.getFileName(), request.getBucket());returnResponseEntity.ok(newInitiateResponse(uploadId));}}@Data@AllArgsConstructor@NoArgsConstructorclassInitiateRequest{privateString fileName;privateString bucket;// 可选,默认使用配置的 bucket}@Data@AllArgsConstructor@NoArgsConstructorclassInitiateResponse{privateString uploadId;}

对应的 Service 方法:

@Service@RequiredArgsConstructorpublicclassFileUploadService{privatefinalMinioClient minioClient;privatefinalString defaultBucket ="file-upload-bucket";publicStringinitiateMultipartUpload(String fileName,String bucket){if(bucket ==null|| bucket.isEmpty()){ bucket = defaultBucket;}try{CreateMultipartUploadResponse response = minioClient.createMultipartUpload(CreateMultipartUploadArgs.builder().bucket(bucket).object(fileName).build());return response.result().uploadId();}catch(Exception e){thrownewRuntimeException("Failed to initiate multipart upload", e);}}}

此方法调用 MinIO 的 createMultipartUpload,返回一个唯一的 uploadId,用于标识本次上传会话。

3. 生成分片预签名 URL

前端拿到 uploadId 后,按需请求每个分片的上传 URL。例如,上传第 1 个分片:

@PostMapping("/presign-part")publicResponseEntity<PresignPartResponse>presignPart(@RequestBodyPresignPartRequest request){String url = fileUploadService.getPresignedUrlForPart( request.getBucket(), request.getFileName(), request.getUploadId(), request.getPartNumber());returnResponseEntity.ok(newPresignPartResponse(url));}@Data@AllArgsConstructor@NoArgsConstructorclassPresignPartRequest{privateString bucket;privateString fileName;privateString uploadId;privateint partNumber;// 从 1 开始}@Data@AllArgsConstructor@NoArgsConstructorclassPresignPartResponse{privateString url;}

Service 实现:

publicStringgetPresignedUrlForPart(String bucket,String object,String uploadId,int partNumber){if(bucket ==null|| bucket.isEmpty()){ bucket = defaultBucket;}try{// 构建分片上传的请求参数Map<String,String> extraQueryParams =newHashMap<>(); extraQueryParams.put("uploadId", uploadId); extraQueryParams.put("partNumber",String.valueOf(partNumber));// 生成预签名 URL,有效期 5 分钟return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.PUT).bucket(bucket).object(object).expiry(5*60)// 5 minutes.extraQueryParams(extraQueryParams).build());}catch(Exception e){thrownewRuntimeException("Failed to generate presigned URL for part "+ partNumber, e);}}

关键点:

  • 通过 extraQueryParams 添加 uploadIdpartNumber,这是 S3 分片上传协议的要求。
  • expiry 设置为 5 分钟,确保安全性。

4. 前端上传分片

前端收到预签名 URL 后,直接使用 fetchaxios 上传分片:

// 伪代码constuploadPart=async(file, start, end, partNumber, presignedUrl)=>{const blob = file.slice(start, end);const response =awaitfetch(presignedUrl,{method:'PUT',body: blob,headers:{'Content-Type':'application/octet-stream'}});const etag = response.headers.get('ETag');// MinIO 返回的 ETagreturn{ partNumber, etag };};
注意:ETag 是 MinIO 对每个分片计算的 MD5 值,后续合并时必须提供。

5. 收集分片信息并完成上传

前端上传完所有分片后,将每个分片的 partNumberETag 发送给后端,触发合并操作:

@PostMapping("/complete")publicResponseEntity<CompleteResponse>completeUpload(@RequestBodyCompleteRequest request){String objectUrl = fileUploadService.completeMultipartUpload( request.getBucket(), request.getFileName(), request.getUploadId(), request.getParts());returnResponseEntity.ok(newCompleteResponse(objectUrl));}@Data@AllArgsConstructor@NoArgsConstructorclassCompleteRequest{privateString bucket;privateString fileName;privateString uploadId;privateList<Part> parts;// 包含 partNumber 和 etag}@Data@AllArgsConstructor@NoArgsConstructorclassPart{privateint partNumber;privateString etag;}@Data@AllArgsConstructor@NoArgsConstructorclassCompleteResponse{privateString objectUrl;}

Service 实现合并逻辑:

publicStringcompleteMultipartUpload(String bucket,String object,String uploadId,List<Part> parts){if(bucket ==null|| bucket.isEmpty()){ bucket = defaultBucket;}try{// 将前端传来的 Part 转换为 MinIO SDK 所需的 Part 类型List<Part> minioParts = parts.stream().map(p ->newPart(p.partNumber, p.etag.replace("\"","")))// 移除 ETag 的引号.sorted(Comparator.comparingInt(Part::partNumber))// 必须按 partNumber 升序.collect(Collectors.toList());CompleteMultipartUploadResponse response = minioClient.completeMultipartUpload(CompleteMultipartUploadArgs.builder().bucket(bucket).object(object).uploadId(uploadId).parts(minioParts).build());// 构造最终的文件访问 URLreturnString.format("%s/%s/%s", minioClient.getRegion(), bucket, object);}catch(Exception e){// 如果合并失败,可选择 abort 上传以清理临时分片try{ minioClient.abortMultipartUpload(AbortMultipartUploadArgs.builder().bucket(bucket).object(object).uploadId(uploadId).build());}catch(Exception abortEx){// 记录日志}thrownewRuntimeException("Failed to complete multipart upload", e);}}

重要细节:

  • ETag 处理:HTTP 响应头中的 ETag 通常带双引号(如 "abc123"),需去除后再传给 MinIO。
  • 排序要求:S3 协议要求 parts 必须按 partNumber 升序排列,否则合并失败。
  • 异常清理:若合并失败,应调用 abortMultipartUpload 删除已上传的分片,避免垃圾数据。

6. (可选)获取文件访问 URL

如果需要生成文件的下载链接(例如用于预览),可再生成一个 GET 类型的预签名 URL:

publicStringgetDownloadUrl(String bucket,String object,int expirySeconds){if(bucket ==null|| bucket.isEmpty()){ bucket = defaultBucket;}try{return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucket).object(object).expiry(expirySeconds).build());}catch(Exception e){thrownewRuntimeException("Failed to generate download URL", e);}}

分片策略与前端配合

分片大小的选择直接影响上传效率和内存使用。常见策略:

  • 固定分片大小:如 5MB、10MB。MinIO 要求每个分片 ≥ 5MB(除最后一个)。
  • 动态分片:根据文件总大小调整。例如:
    • < 100MB:不分片,直接上传。
    • 100MB ~ 1GB:每片 10MB。
1GB:每片 50MB 或 100MB。

前端需实现文件切片逻辑:

functioncalculateChunks(fileSize, chunkSize =10*1024*1024){const chunks =[];let start =0;let partNumber =1;while(start < fileSize){const end = Math.min(start + chunkSize, fileSize); chunks.push({ start, end, partNumber }); start = end; partNumber++;}return chunks;}
⚠️ 注意:最后一个分片可以小于 5MB,但其他分片必须 ≥ 5MB,否则 MinIO 会拒绝。

异常处理与重试机制

网络环境复杂,上传过程中可能出现各种异常:

  • 分片上传超时
  • 预签名 URL 过期
  • ETag 不匹配
  • 服务端错误

前端重试策略

  • 对每个分片上传实现指数退避重试(如最多 3 次)。
  • 若预签名 URL 过期,重新向后端请求新的 URL。
  • 记录已成功上传的分片,避免重复上传。

后端清理机制

长时间未完成的分片上传会占用存储空间。MinIO 提供了生命周期管理(Lifecycle Management)功能,可自动清理过期的未完成上传。

你也可以在后端定期扫描并清理:

publicvoidcleanupStaleUploads(String bucket,Duration maxAge){try{ListMultipartUploadsResponse response = minioClient.listMultipartUploads(ListMultipartUploadsArgs.builder().bucket(bucket).build());Instant now =Instant.now();for(Result<MultipartUpload> upload : response.result().uploads()){MultipartUpload u = upload.get();if(Duration.between(u.initiated().toInstant(), now).compareTo(maxAge)>0){ minioClient.abortMultipartUpload(AbortMultipartUploadArgs.builder().bucket(bucket).object(u.object()).uploadId(u.uploadId()).build());}}}catch(Exception e){// log error}}

可配合 Spring 的 @Scheduled 定时任务每天执行一次。


安全性考量

虽然预签名 URL 提供了便利,但也带来安全风险,需谨慎处理:

1. URL 有效期

  • 始终设置较短的有效期(如 5 分钟)。
  • 不要将 URL 永久暴露或缓存。

2. 权限最小化

  • MinIO 的访问密钥应遵循最小权限原则。上传服务使用的账号只应有 s3:PutObject, s3:CreateMultipartUpload 等必要权限。
  • 可通过 IAM 策略或桶策略限制操作。

3. 文件类型校验

  • 前端可伪造文件扩展名。后端应在 initiate 阶段校验文件类型(如通过 Magic Number)。
  • 限制允许的 MIME 类型和文件大小。
@PostMapping("/initiate")publicResponseEntity<InitiateResponse>initiateUpload(@RequestBodyInitiateRequest request){// 示例:只允许图片String ext =getFileExtension(request.getFileName()).toLowerCase();if(!Set.of("jpg","jpeg","png","gif").contains(ext)){thrownewIllegalArgumentException("Unsupported file type");}// ... 其他校验}

4. 防止路径遍历

  • 用户提供的文件名可能包含 ../,导致写入非法路径。
  • 应对文件名进行清洗或使用 UUID 重命名。
String safeFileName = UUID.randomUUID()+"."+ ext;

性能优化建议

1. 并行上传分片

前端可同时上传多个分片(如并发 4~6 个),大幅提升大文件上传速度。

2. 使用 CDN 加速下载

上传完成后,可通过 CDN 分发文件。MinIO 可与 Nginx、Cloudflare 等集成。

3. 后端异步处理

complete 操作可能耗时(尤其大文件),可改为异步:

  • 前端上传完分片后,后端立即返回“处理中”。
  • 后台线程池执行 completeMultipartUpload
  • 前端轮询或通过 WebSocket 获取最终结果。

4. 监控与日志

  • 记录每次上传的 uploadId、文件大小、耗时等指标。
  • 集成 Prometheus + Grafana 监控 MinIO 性能。

测试与验证

单元测试

使用 Testcontainers 启动真实 MinIO 实例进行集成测试:

@Testcontainers@SpringBootTestclassFileUploadServiceTest{@ContainerstaticMinIOContainer minio =newMinIOContainer("minio/minio:RELEASE.2023-10-23T03-42-26Z");@AutowiredprivateFileUploadService fileUploadService;@TestvoidtestMultipartUpload(){// 1. initiateString uploadId = fileUploadService.initiateMultipartUpload("test.txt","test-bucket");assertNotNull(uploadId);// 2. upload part via presigned URL (mock or real HTTP call)// 3. complete// 4. verify object exists}}
注意:Testcontainers 需要 Docker 环境。

手动测试

  1. 启动 MinIO 和 Java 应用。
  2. 使用 Postman 或 curl 调用 /initiate
  3. 获取 uploadId
  4. 请求第一个分片的预签名 URL。
  5. 记录返回的 ETag。
  6. 调用 /complete 合并。
  7. 在 MinIO 控制台查看文件是否生成。

用 curl 上传一个文本分片:

curl -X PUT -H "Content-Type: text/plain" --data "Hello Part 1""http://localhost:9000/...?uploadId=...&partNumber=1"

常见问题排查

Q1: 分片上传返回 403 Forbidden

  • 检查 MinIO 的访问密钥是否正确。
  • 确认账号是否有 s3:PutObject 权限。
  • 预签名 URL 是否包含正确的 uploadIdpartNumber

Q2: Complete 时提示 “InvalidPart”

  • 分片 ETag 未去除双引号。
  • parts 列表未按 partNumber 排序。
  • 某些分片未成功上传。

Q3: 预签名 URL 无法访问

  • 检查 MinIO 的 endpoint 配置是否为公网可访问地址(开发环境常用 http://host.docker.internal:9000)。
  • 确保 URL 未过期。

Q4: 大文件上传慢

  • 增加前端并发分片数。
  • 检查网络带宽和 MinIO 磁盘 I/O。
  • 考虑使用更大的分片(如 50MB)。

扩展:断点续传支持

要实现真正的断点续传,需在后端记录每个上传任务的状态:

  1. 创建 UploadSession 表,记录 uploadId, fileName, totalParts, uploadedParts
  2. 每次前端上报分片 ETag,更新 uploadedParts
  3. 用户重新上传时,先查询已有 session,返回已上传的分片列表。
  4. 前端只上传缺失的分片。

这需要引入数据库(如 MySQL 或 Redis),但能极大提升用户体验。


总结

通过结合 MinIO 的分片上传预签名 URL,我们构建了一个高性能、高可靠、安全的文件上传中间件。它具备以下优势:

  • 📤 前端直传:减轻后端带宽压力。
  • 🧩 分片容错:支持大文件、断点续传。
  • 🔐 临时授权:通过预签名 URL 实现细粒度权限控制。
  • 🛠️ 易于扩展:可集成校验、异步处理、监控等模块。

在实际项目中,还需根据业务场景调整分片策略、安全策略和错误处理机制。MinIO 作为轻量级对象存储,完美适配微服务架构,是替代商业 S3 服务的理想选择。

希望本文的详细讲解和代码示例能为你在 Java 项目中集成 MinIO 提供坚实基础。 Happy Coding! 💻✨

参考资料:MinIO 官方文档:https://min.io/docs/minio/linux/index.htmlAWS S3 分片上传指南:https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.htmlMinIO Java SDK GitHub Wiki(仅作参考,不提供链接)

🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Read more

[源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精

[源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精

文章目录 * [源力觉醒 创作者计划]_文心一言 4.5开源深度解析:性能狂飙 + 中文专精 * 一. 部署实战:单卡环境的极速落地 * 1.1 🖥️ 环境配置の手把手教程 📝 * 部署准备:硬件与镜像 * 依赖安装:一行代码搞定 * 1.2 🚀 模型启动の参数与验证 ✅. * 二. 多场景能力验证:从工业到学术 * 2.1 🏥 医疗影像诊断:从模糊影像到病灶定位 * 2.2 🚦 交通流优化:动态拥堵预测与策略设计 * 2.3 🔍 考古文本破译:甲骨文符号的跨学科解读 * 三. 性能优化与问题解决 * 3.1 🚀 性能优化策略:让模型跑得更快 * 3.2 🛠️ 常见错误解决方案 * 四. 与同类模型对比 * 🍬 核心优势对比🍭 * 🍬 对比结论🍭 * 五、

By Ne0inhk
LLaMA-Factory微调多模态大模型Qwen3-VL

LLaMA-Factory微调多模态大模型Qwen3-VL

LLaMA-Factory微调多模态大模型Qwen3-VL 目录 LLaMA-Factory微调多模态大模型Qwen3-VL 1. 显卡驱动 2. 模型微调 3. 模型导出 4. 模型部署:vLLM服务 5. 测试效果 1. 显卡驱动 * 显卡型号:NVIDIA GeForce RTX 3090 24G * 显卡驱动:NVIDIA-SMI 535.171.04             * CUDA: 12.2 ,Driver Version: 535.171.04   微调Qwen3-VL-2B模型,至少需要12G显存 2. 模型微调 项目采用大型语言模型工厂(LLaMA-Factory)对大模型微调,目前可支持Qwen3 / Qwen2.5-VL / Gemma 3 / GLM-4.1V / InternLM

By Ne0inhk

Llama-Recipes数据备份终极指南:增量备份与快照技术详解

Llama-Recipes数据备份终极指南:增量备份与快照技术详解 【免费下载链接】llama-recipesExamples and recipes for Llama 2 model 项目地址: https://gitcode.com/gh_mirrors/ll/llama-recipes 在Llama大语言模型应用开发过程中,数据备份和快照技术是确保模型训练安全性和项目稳定性的关键。llama-recipes项目提供了完善的模型检查点管理方案,让开发者能够高效地进行增量备份和创建训练快照。🚀 为什么需要数据备份策略? 在大规模模型训练过程中,一次完整的训练可能需要数小时甚至数天时间。如果遇到硬件故障、程序错误或意外中断,没有备份机制将导致巨大的时间和资源浪费。llama-recipes通过智能的检查点系统,实现了: * 训练过程保护:防止意外中断导致的数据丢失 * 模型版本管理:保存不同训练阶段的模型状态 * 资源优化:减少重复训练的成本 增量备份技术详解 llama-recipes采用先进的增量备份策略,在checkpoint_handler.py中实

By Ne0inhk
一文带你掌握Visual Studio中集成的git功能

一文带你掌握Visual Studio中集成的git功能

前言 Visual Studio中深度集成了git功能,可以很方便的进行源代码版本控制功能。 大部分日常的操作我们可以通过界面来完成,这样就省去了输入git命令的时间,也可以不用记很多参数。 但这毕竟是辅助工具,掌握常用的git命令行还是很有必要的。 言归正传,接下来开始介绍Visual Studio 中集成的git功能。 本文以Visual Studio 2022为例进行演示 安装 Visual Studio的UI中已经集成了git相关功能,但是也需要安装git后才能使用。 如果没有安装git,在使用相关功能时,可能会看到如下的提示 安装方式可以通过以下两种 1、在Visual Studio的安装程序中,钩选<适用于Windows的Git> 推荐使用这种方式,因为免去了单独下载和安装的环节 2、访问git官方网站,下载安装包手动安装 下载地址:Git - Install for Windows 导入/克隆(clone)代码 方法1、在Visual Studio的启动界面上选择克隆存储库 输入

By Ne0inhk