一、DeepSeek版
要使用Java列出Amazon S3中的所有目录和子目录路径,可以使用AWS SDK for Java (v2)。以下是完整的实现方法:
方法1:使用S3Client和listObjectsV2
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import software.amazon.awssdk.services.s3.model.S3Object;
import java.util.HashSet;
import java.util.Set;
public class S3DirectoryLister {
    public static void main(String[] args) {
        String bucketName = "your-bucket-name";
        String prefix = ""; // 可以从特定前缀开始
        
        Set<String> directories = listS3Directories(bucketName, prefix);
        
        System.out.println("Found directories:");
        directories.forEach(System.out::println);
    }
    public static Set<String> listS3Directories(String bucketName, String prefix) {
        S3Client s3 = S3Client.builder()
                .region(Region.US_EAST_1) // 更改为你的区域
                .build();
        Set<String> directories = new HashSet<>();
        ListObjectsV2Request request = ListObjectsV2Request.builder()
                .bucket(bucketName)
                .prefix(prefix)
                .delimiter("/")
                .build();
        ListObjectsV2Response response;
        do {
            response = s3.listObjectsV2(request);
            
            // 添加CommonPrefixes(目录)
            if (response.commonPrefixes() != null) {
                response.commonPrefixes().forEach(commonPrefix -> {
                    String dirPath = commonPrefix.prefix();
                    directories.add(dirPath);
                    // 递归列出子目录
                    directories.addAll(listS3Directories(bucketName, dirPath));
                });
            }
            
            // 处理下一页(如果有)
            request = request.toBuilder()
                    .continuationToken(response.nextContinuationToken())
                    .build();
        } while (response.isTruncated());
        s3.close();
        return directories;
    }
}
方法2:使用TransferManager(更高效)
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import software.amazon.awssdk.services.s3.model.CommonPrefix;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class S3AsyncDirectoryLister {
    public static void main(String[] args) {
        String bucketName = "your-bucket-name";
        String prefix = "";
        
        Set<String> directories = new HashSet<>();
        listS3DirectoriesAsync(S3AsyncClient.create(), bucketName, prefix, directories)
            .thenRun(() -> {
                System.out.println("Found directories:");
                directories.forEach(System.out::println);
                System.exit(0);
            })
            .exceptionally(e -> {
                e.printStackTrace();
                return null;
            });
        
        // 保持程序运行直到完成
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    public static CompletableFuture<Void> listS3DirectoriesAsync(
            S3AsyncClient s3AsyncClient, 
            String bucketName, 
            String prefix, 
            Set<String> directories) {
        
        ListObjectsV2Request request = ListObjectsV2Request.builder()
                .bucket(bucketName)
                .prefix(prefix)
                .delimiter("/")
                .build();
        return s3AsyncClient.listObjectsV2(request)
                .thenCompose(response -> {
                    // 处理当前响应
                    if (response.commonPrefixes() != null) {
                        for (CommonPrefix commonPrefix : response.commonPrefixes()) {
                            String dirPath = commonPrefix.prefix();
                            directories.add(dirPath);
                        }
                        
                        // 为每个子目录启动新的异步请求
                        CompletableFuture<?>[] futures = response.commonPrefixes().stream()
                                .map(commonPrefix -> 
                                    listS3DirectoriesAsync(s3AsyncClient, bucketName, 
                                        commonPrefix.prefix(), directories))
                                .toArray(CompletableFuture<?>[]::new);
                        
                        return CompletableFuture.allOf(futures);
                    }
                    return CompletableFuture.completedFuture(null);
                });
    }
}
注意事项
- 
	
确保你已经配置了AWS凭证,可以通过:
- 环境变量
 - 凭证文件 (~/.aws/credentials)
 - IAM角色(如果在EC2上运行)
 
 - 
	
需要添加AWS SDK依赖到你的项目中(Maven示例):|
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> <version>2.17.0</version> <!-- 使用最新版本 --> </dependency> - 
	
对于大型S3存储桶,可能需要增加超时设置或处理分页。
 - 
	
第一个方法是同步的,适用于简单场景;第二个方法是异步的,性能更好但更复杂。
 - 
	
记得在完成后关闭客户端以释放资源。
 
二、豆包版
以下是一个 Java 程序,用于列出 AWS S3 存储桶中的所有目录和子目录路径。程序使用 AWS SDK for Java v2,通过递归方式遍历所有对象并提取目录结构。
S3ListDirectories.java 文件内容:
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import software.amazon.awssdk.services.s3.model.S3Object;
import java.util.*;
public class S3ListDirectories {
    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("请提供S3存储桶名称作为参数");
            return;
        }
        String bucketName = args[0];
        Region region = Region.US_EAST_1; // 根据实际情况修改区域
        // 创建S3客户端
        S3Client s3Client = S3Client.builder()
                .region(region)
                .credentialsProvider(ProfileCredentialsProvider.create())
                .build();
        // 存储所有目录路径的集合(自动去重)
        Set<String> directories = new TreeSet<>();
        // 列出所有对象并提取目录
        listObjectsAndExtractDirectories(s3Client, bucketName, "", directories);
        // 输出所有目录
        System.out.println("S3存储桶 " + bucketName + " 中的目录结构:");
        for (String directory : directories) {
            System.out.println(directory);
        }
        s3Client.close();
    }
    private static void listObjectsAndExtractDirectories(S3Client s3Client, String bucketName, String prefix, Set<String> directories) {
        ListObjectsV2Request request = ListObjectsV2Request.builder()
                .bucket(bucketName)
                .prefix(prefix)
                .delimiter("/")
                .build();
        ListObjectsV2Response response;
        String continuationToken = null;
        do {
            // 如果有继续标记,则设置它
            if (continuationToken != null) {
                request = request.toBuilder().continuationToken(continuationToken).build();
            }
            response = s3Client.listObjectsV2(request);
            // 处理CommonPrefixes(目录)
            if (response.commonPrefixes() != null) {
                for (var commonPrefix : response.commonPrefixes()) {
                    String directory = commonPrefix.prefix();
                    directories.add(directory);
                    // 递归处理子目录
                    listObjectsAndExtractDirectories(s3Client, bucketName, directory, directories);
                }
            }
            continuationToken = response.nextContinuationToken();
        } while (response.isTruncated());
    }
}    
使用说明
- 依赖配置:确保在你的项目中添加 AWS SDK for Java v2 的依赖。如果你使用 Maven,可以添加以下依赖:
 
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.20.95</version>
</dependency>
- 
	
凭证配置:程序使用默认凭证提供者链,你需要配置 AWS 凭证。推荐的方法是:
- 在你的计算机上安装 AWS CLI
 - 运行
aws configure命令配置访问密钥和区域 
 - 
	
运行程序:编译并运行程序,将 S3 存储桶名称作为命令行参数传递:
 
java S3ListDirectories your-bucket-name
程序功能说明
- 程序会递归遍历指定 S3 存储桶中的所有对象和子目录
 - 使用
TreeSet存储目录路径,确保自动去重并按字典序排序 - 通过
delimiter参数识别目录结构 - 处理分页结果,确保获取所有对象
 - 输出格式为完整的目录路径,以斜杠结尾
 
工作中的版本
文件名:WarehouseImageS3Service.java
package com.fuyo.application.warehouse_image.service.extend;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import java.util.Set;
import java.util.TreeSet;
/**
 * 仓库过机图片S3服务类
 */
@Slf4j
@Service
public class WarehouseImageS3Service {
    /**
     * 同步S3文件
     */
    public void syncS3Files() {
        String accessKeyId = "AKIAUE5KS4KYSUUxxxxx";
        String secretAccessKey = "2biqCTFqaywgExvz0I/vG2UgwkCWamOByyyyyyyy";
        // 存储桶名
        // String bucketName = "warehouse-pictures";
        // String prefix = "";
        
        String bucketName = "albert-test";
        String prefix = "";
        // 创建S3客户端
        S3Client s3Client = createClient(accessKeyId, secretAccessKey, Region.CN_NORTH_1);
        // 存储所有目录路径的集合(自动去重)
        Set<String> directories = new TreeSet<>();
        // 列出所有对象并提取目录
        listObjectsAndExtractDirectories(s3Client, bucketName, prefix, directories);
        s3Client.close();
        // 输出所有目录
        System.out.println("S3存储桶 " + bucketName + " 中的目录结构:");
        for (String directory : directories) {
            System.out.println(directory);
        }
    }
    /**
     * 创建S3客户端
     *
     * @param accessKeyId     账号
     * @param secretAccessKey 密码
     * @param region          区域
     */
    public S3Client createClient(String accessKeyId, String secretAccessKey, Region region) {
        AwsBasicCredentials credentials = AwsBasicCredentials.create(
            accessKeyId,
            secretAccessKey
        );
        // 创建S3客户端
        return S3Client.builder()
            .region(region)
            .credentialsProvider(StaticCredentialsProvider.create(credentials))
            .build();
    }
    private void listObjectsAndExtractDirectories(S3Client s3Client, String bucketName, String prefix, Set<String> directories) {
        ListObjectsV2Request request = ListObjectsV2Request.builder()
            .bucket(bucketName)
            .prefix(prefix)
            .delimiter("/")
            .build();
        ListObjectsV2Response response;
        String continuationToken = null;
        do {
            // 如果有继续标记,则设置它
            if (continuationToken != null) {
                request = request.toBuilder().continuationToken(continuationToken).build();
            }
            response = s3Client.listObjectsV2(request);
            // 处理CommonPrefixes(目录)
            if (response.commonPrefixes() != null) {
                for (var commonPrefix : response.commonPrefixes()) {
                    String directory = commonPrefix.prefix();
                    directories.add(directory);
                    // 递归处理子目录
                    listObjectsAndExtractDirectories(s3Client, bucketName, directory, directories);
                }
            }
            continuationToken = response.nextContinuationToken();
        } while (response.isTruncated());
    }
    
}
输出:
S3存储桶 albert-test 中的目录结构: dg/ dg/2025/ dg/2025/06/ dg/2025/06/17/ dg/2025/06/18/ dg/2025/06/19/ nb/ nb/2025/