访问S3存储桶时遭遇java.io.FileNotFoundException问题求助
兄弟,我之前做Lambda处理S3文件的时候也踩过这个java.io.FileNotFoundException的坑,大概率是这几个原因导致的,给你一步步排查:
1. 错误地用本地文件路径访问S3对象
S3的存储对象并不是Lambda执行环境本地文件系统里的文件,你要是直接用new File(objectKey)这种方式去访问,肯定会报找不到文件的错误。正确的姿势是用AWS SDK的S3客户端获取对象的输入流来读取内容。
2. Lambda执行角色缺少S3读取权限
如果你的Lambda角色没有s3:GetObject权限,就算路径对了也读不到S3文件。需要给Lambda的IAM角色添加如下策略(记得替换成你的桶名):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::your-bucket-name/*" } ] }
3. S3对象键的URL编码问题
S3事件里返回的对象键可能是URL编码后的(比如空格会变成%20),如果直接用这个编码后的键去调用getObject,会找不到对应的对象。你需要先解码:
import java.net.URLDecoder; // ... String encodedKey = s3event.getRecords().get(0).getS3().getObject().getKey(); String objectKey = URLDecoder.decode(encodedKey, "UTF-8");
4. S3桶区域与Lambda客户端区域不匹配
你代码里硬编码了US_EAST_1区域,但如果你的S3桶在其他区域(比如US_WEST_2),客户端和桶区域不匹配也会导致访问失败。建议不要硬编码区域,用默认客户端会自动匹配Lambda执行环境的区域:
private final AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
给你一个修正后的代码示例
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.S3Event; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.S3Object; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URLDecoder; public class LambdaFunctionHandler implements RequestHandler<S3Event, Report> { // 使用默认客户端,自动匹配区域 private final AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient(); public Report handleRequest(S3Event s3event, Context context) { long startTime = System.currentTimeMillis(); Report statusReport = new Report(); try { // 从S3事件中获取桶名和编码后的对象键 String bucketName = s3event.getRecords().get(0).getS3().getBucket().getName(); String encodedObjectKey = s3event.getRecords().get(0).getS3().getObject().getKey(); // 解码对象键,处理特殊字符 String objectKey = URLDecoder.decode(encodedObjectKey, "UTF-8"); // 通过S3客户端获取对象输入流 S3Object s3Object = s3Client.getObject(bucketName, objectKey); // 读取CSV内容并输出到CloudWatch日志 BufferedReader reader = new BufferedReader(new InputStreamReader(s3Object.getObjectContent())); String line; while ((line = reader.readLine()) != null) { context.getLogger().log("CSV line: " + line); } statusReport.setSuccess(true); statusReport.setMessage("File read successfully"); } catch (IOException e) { context.getLogger().log("Error reading file: " + e.getMessage()); statusReport.setSuccess(false); statusReport.setMessage(e.getMessage()); } long endTime = System.currentTimeMillis(); statusReport.setProcessingTime(endTime - startTime); return statusReport; } }
最后再提醒下:测试的时候可以手动构造S3事件触发Lambda,或者确保S3桶的事件通知配置正确,把触发条件设为你需要的文件上传事件。
内容的提问来源于stack exchange,提问作者Binay Kumar
相关产品推荐
相关产品推荐

