You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AWS Java SDK上传文件至S3时MD5计算失败,报FileNotFoundException

S3文件上传EC2生产环境异常排查与修复

问题概述

使用AWS SDK实现S3存储桶文件上传功能,本地环境运行正常,但部署到EC2生产实例时出现文件找不到的错误。

代码片段

上传逻辑

File fileObj = DocumentUtils.convertMultiPartFileToFile(file);
User user = userService.getUserDetailsViaHttpHeader(httpHeaders);
String filePath = user.getId().toString() + "/" + "KMLFiles" + "/" + "KML" + "_" + System.currentTimeMillis() + ".kml";
PutObjectResult putObjectRequest = s3Client.putObject(awsBucketName, filePath, fileObj);

MultipartFile转File方法

public static File convertMultiPartFileToFile(MultipartFile file) {
    File convertedFile = new File(file.getOriginalFilename());
    try (FileOutputStream fos = new FileOutputStream(convertedFile)) {
        fos.write(file.getBytes());
    } catch (IOException e) {
    }
    return convertedFile;
}

依赖配置

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.12.370</version>
</dependency>

错误日志

May 13 19:26:52 ip-172-31-27-27 java[20208]: 2023-05-13 19:26:52.717 DEBUG 20208 --- [nio-9096-exec-4] o.s.web.servlet.DispatcherServlet        : Failed to complete request: com.amazonaws.SdkClientException: Unable to calculate MD5 hash: Test.kml (No such file or directory)
May 13 19:26:52 ip-172-31-27-27 java[20208]: 2023-05-13 19:26:52.721 ERROR 20208 --- [nio-9096-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.amazonaws.SdkClientException: Unable to calculate MD5 hash: Test.kml (No such file or directory)] with root cause
May 13 19:26:52 ip-172-31-27-27 java[20208]: java.io.FileNotFoundException: Test.kml (No such file or directory)
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at java.base/java.io.FileInputStream.open0(Native Method) ~[na:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at java.base/java.io.FileInputStream.open(FileInputStream.java:219) ~[na:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157) ~[na:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at com.amazonaws.util.Md5Utils.computeMD5Hash(Md5Utils.java:97) ~[aws-java-sdk-core-1.12.370.jar!/:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at com.amazonaws.util.Md5Utils.md5AsBase64(Md5Utils.java:104) ~[aws-java-sdk-core-1.12.370.jar!/:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at com.amazonaws.services.s3.AmazonS3Client.getInputStream(AmazonS3Client.java:1920) ~[aws-java-sdk-s3-1.12.370.jar!/:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at com.amazonaws.services.s3.AmazonS3Client.uploadObject(AmazonS3Client.java:1842) ~[aws-java-sdk-s3-1.12.370.jar!/:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1821) ~[aws-java-sdk-s3-1.12.370.jar!/:na]
May 13 19:26:52 ip-172-31-27-27 java[20208]: #011at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1746) ~[aws-java-sdk-s3-1.12.370.jar!/:na]

额外观察

  • 本地环境上传功能运行完全正常
  • 生产环境S3访问凭证配置正确

问题根源

  1. 路径与权限问题:convertMultiPartFileToFile方法中直接用文件名创建文件,默认会在应用当前工作目录生成文件。EC2实例中应用进程可能没有该目录的写入权限,导致文件实际未创建成功。
  2. 异常被掩盖:方法中的空catch块吞掉了文件写入时的IO异常,无法及时发现文件创建失败的问题,直到AWS SDK读取文件时才抛出找不到文件的错误。

修复方案

方案一:修复临时文件创建逻辑

使用系统临时目录创建文件,确保权限合法,同时添加异常处理:

import org.apache.commons.io.FilenameUtils;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.File;

public static File convertMultiPartFileToFile(MultipartFile file) throws IOException {
    // 基于原文件名后缀创建临时文件,避免文件名冲突
    File convertedFile = File.createTempFile("kml-temp-", "." + FilenameUtils.getExtension(file.getOriginalFilename()));
    try (FileOutputStream fos = new FileOutputStream(convertedFile)) {
        fos.write(file.getBytes());
    }
    // JVM退出时自动删除临时文件,避免磁盘占用
    convertedFile.deleteOnExit();
    return convertedFile;
}

方案二:优化为直接流上传(推荐)

跳过本地文件创建步骤,直接使用MultipartFile的输入流上传到S3,彻底避免本地文件相关问题:

User user = userService.getUserDetailsViaHttpHeader(httpHeaders);
String filePath = user.getId().toString() + "/KMLFiles/KML_" + System.currentTimeMillis() + ".kml";

// 构建文件元数据,设置ContentType和文件大小
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(file.getContentType());
metadata.setContentLength(file.getSize());

// 使用输入流直接上传
PutObjectResult putObjectRequest = s3Client.putObject(
    new PutObjectRequest(awsBucketName, filePath, file.getInputStream(), metadata)
);

说明

  • 方案一解决了权限和路径问题,同时保留了文件上传的原有逻辑;
  • 方案二更高效,减少了本地IO操作,避免了所有本地文件相关的潜在问题,是推荐的优化方向;
  • 无论采用哪种方案,都不要吞掉IO异常,需抛出或打印日志,方便后续排查问题。

内容的提问来源于stack exchange,提问作者Aditya Rewari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:32:48