如何用Java实现带文件夹校验的S3文件夹条件式对象写入?
刚好做过类似的S3批量处理需求,我来给你一个完整的Java实现方案,完全符合你的要求👇
Java实现S3按记录批量创建文件夹并写入对象
需求梳理
先明确下你的核心需求:
逐条遍历记录,以记录首字段作为S3文件夹名称,先检查该文件夹是否存在,不存在则创建;仅当目标文件夹内现有对象数量小于10时,将记录第二字段作为对象Key、第三字段作为对象Value写入对应S3文件夹。
示例记录:1,abc,def;2,xyz,mno;1,ghi,lks;2,dec,frt;3,uhy,erw,处理后生成S3文件夹1/、2/、3/,对应文件夹下存储abc.txt、ghi.txt等对象。
实现思路
首先得明确S3的一个核心特性:没有真正的物理文件夹,所谓的“文件夹”其实是对象Key的前缀(比如1/)。基于这个特性,我们的实现步骤是:
- 遍历每条记录,拆分出文件夹前缀、对象名称、对象内容
- 检查对应前缀的“文件夹”是否存在(通过判断是否有以
/结尾的空对象),不存在则创建 - 统计该前缀下的对象数量(排除文件夹本身的空对象),如果小于10则写入对象
- 使用AWS SDK for Java 2.x(当前官方推荐版本)来完成所有S3操作
依赖准备
首先需要在你的项目中引入AWS S3的SDK依赖,以Maven为例:
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> <version>2.20.100</version> <!-- 可以使用最新稳定版 --> </dependency>
完整代码实现
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.*; import java.util.List; public class S3RecordProcessor { // 替换成你的目标S3桶名 private static final String BUCKET_NAME = "your-target-bucket"; private static final S3Client s3Client; static { // 初始化S3客户端,使用默认凭证链(支持环境变量、凭证文件等) s3Client = S3Client.builder() .region(Region.US_EAST_1) // 替换成你的桶所在区域 .credentialsProvider(DefaultCredentialsProvider.create()) .build(); } public static void main(String[] args) { // 示例记录列表,实际中可以从CSV文件、数据库或消息队列读取 List<String> records = List.of( "1,abc,def", "2,xyz,mno", "1,ghi,lks", "2,dec,frt", "3,uhy,erw" ); // 逐条处理记录 for (String record : records) { processSingleRecord(record); } // 关闭客户端释放资源 s3Client.close(); } /** * 处理单条记录的核心逻辑 */ private static void processSingleRecord(String record) { // 拆分记录,确保格式正确 String[] recordParts = record.split(","); if (recordParts.length != 3) { System.err.println("跳过无效记录: " + record); return; } String folderName = recordParts[0]; String objectBaseKey = recordParts[1]; String objectContent = recordParts[2]; // 构造S3中的文件夹前缀(必须以/结尾,模拟文件夹) String folderPrefix = folderName + "/"; // 最终对象Key:文件夹前缀 + 基础Key + .txt后缀 String targetObjectKey = folderPrefix + objectBaseKey + ".txt"; // 步骤1:确保文件夹(前缀)存在 ensureFolderExists(folderPrefix); // 步骤2:统计该文件夹下的对象数量 int currentObjectCount = getObjectCountInFolder(folderPrefix); if (currentObjectCount < 10) { // 步骤3:写入对象到S3 putObjectToS3(targetObjectKey, objectContent); System.out.println("成功写入对象: " + targetObjectKey); } else { System.out.println("文件夹" + folderName + "下对象已达10个,跳过写入: " + targetObjectKey); } } /** * 确保S3中的文件夹(前缀)存在,不存在则创建空对象模拟文件夹 */ private static void ensureFolderExists(String folderPrefix) { try { // 检查是否存在文件夹对象(以/结尾的空对象) HeadObjectRequest headRequest = HeadObjectRequest.builder() .bucket(BUCKET_NAME) .key(folderPrefix) .build(); s3Client.headObject(headRequest); } catch (NoSuchKeyException e) { // 不存在则创建空对象 PutObjectRequest putFolderRequest = PutObjectRequest.builder() .bucket(BUCKET_NAME) .key(folderPrefix) .build(); s3Client.putObject(putFolderRequest, software.amazon.awssdk.core.sync.RequestBody.empty()); System.out.println("创建文件夹: " + folderPrefix); } } /** * 获取指定文件夹前缀下的对象数量(排除文件夹本身的空对象) * 处理S3分页返回的情况(单次最多返回1000个对象) */ private static int getObjectCountInFolder(String folderPrefix) { ListObjectsV2Request listRequest = ListObjectsV2Request.builder() .bucket(BUCKET_NAME) .prefix(folderPrefix) .delimiter("/") // 只统计当前文件夹下的直接对象,不递归子文件夹 .build(); ListObjectsV2Response response = s3Client.listObjectsV2(listRequest); int count = 0; // 统计第一页的对象 for (S3Object s3Object : response.contents()) { // 排除文件夹本身的空对象 if (!s3Object.key().equals(folderPrefix)) { count++; } } // 处理分页,直到获取所有对象 while (response.isTruncated()) { listRequest = ListObjectsV2Request.builder() .bucket(BUCKET_NAME) .prefix(folderPrefix) .delimiter("/") .continuationToken(response.nextContinuationToken()) .build(); response = s3Client.listObjectsV2(listRequest); for (S3Object s3Object : response.contents()) { if (!s3Object.key().equals(folderPrefix)) { count++; } } } return count; } /** * 将文本内容写入指定的S3对象 */ private static void putObjectToS3(String objectKey, String content) { PutObjectRequest putRequest = PutObjectRequest.builder() .bucket(BUCKET_NAME) .key(objectKey) .contentType("text/plain") // 设置内容类型为纯文本 .build(); s3Client.putObject(putRequest, software.amazon.awssdk.core.sync.RequestBody.fromString(content)); } }
关键细节说明
- S3文件夹模拟:通过创建以
/结尾的空对象来模拟文件夹,这样在S3控制台中会显示为文件夹结构,方便管理。 - 对象数量统计:使用
ListObjectsV2API并设置delimiter="/",确保只统计当前文件夹下的直接对象,不会递归子文件夹。同时处理了分页逻辑,避免因为对象数量超过1000导致统计不全。 - 凭证管理:使用默认凭证提供器,会自动从环境变量、AWS凭证文件(
~/.aws/credentials)、IAM角色(如果在EC2/EKS等AWS服务中运行)获取凭证,无需硬编码。 - 扩展性:你可以根据实际需求扩展错误处理(比如重试写入、记录详细日志)、记录来源(比如从CSV文件读取)等功能。
内容的提问来源于stack exchange,提问作者Akshat Choudhary
相关产品推荐
相关产品推荐

