如何在Java中通过通配符路径模式仅列出S3中匹配规则的文件
Java实现S3通配符路径匹配文件的方案
首先明确:AWS S3本身的原生API不直接支持通配符、正则匹配过滤对象,所有筛选逻辑都需要先拉取指定前缀下的对象列表,再在本地做模式匹配,以下是可直接落地的实现方案:
方案1:AWS SDK for Java + 正则匹配(最通用方案)
步骤如下:
- 首先拆分路径模式,提取固定前缀缩小S3拉取范围:你给出的模式
s3://dataai/alarms/Json/mydata/[0-9]*/[0-9]*/[0-9]*/*_01.json的固定前缀是s3://dataai/alarms/Json/mydata/,只拉取该前缀下的所有对象,避免拉取无关文件减少IO开销 - 将通配符模式转为Java正则表达式:
[0-9]*对应正则\d*,*对应正则[^/]*(避免跨目录匹配),最终转换后的正则为^alarms/Json/mydata/\d*/\d*/\d*/[^/]*_01\.json$(注意S3对象key不带bucket名,所以正则里去掉开头的s3://dataai/) - 调用S3 ListObjectsV2 API拉取指定前缀下的所有对象,遍历每个对象的key用正则匹配,符合规则的就保留
示例代码片段
import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.*; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; public class S3WildcardMatcher { public static void main(String[] args) { S3Client s3Client = S3Client.create(); String bucketName = "dataai"; String fixedPrefix = "alarms/Json/mydata/"; // 转换后的正则表达式 Pattern pattern = Pattern.compile("^alarms/Json/mydata/\\d*/\\d*/\\d*/[^/]*_01\\.json$"); List<String> matchedKeys = new ArrayList<>(); ListObjectsV2Request request = ListObjectsV2Request.builder() .bucket(bucketName) .prefix(fixedPrefix) .build(); ListObjectsV2Iterable response = s3Client.listObjectsV2Paginator(request); for (S3Object s3Object : response.contents()) { String key = s3Object.key(); if (pattern.matcher(key).matches()) { matchedKeys.add("s3://" + bucketName + "/" + key); } } // 输出匹配结果 matchedKeys.forEach(System.out::println); } }
方案2:Hadoop AWS库(适合已有Hadoop依赖的项目)
如果你的项目已经引入了Hadoop相关依赖,可以直接用org.apache.hadoop.fs.s3a.S3AFileSystem提供的globStatus方法,原生支持通配符路径匹配,不用自己写正则转换逻辑,示例用法:
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.s3a.S3AFileSystem; import java.net.URI; public class S3HadoopMatcher { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); S3AFileSystem fs = new S3AFileSystem(); fs.initialize(URI.create("s3://dataai/"), conf); // 直接传入通配符路径即可 FileStatus[] statuses = fs.globStatus(new Path("s3://dataai/alarms/Json/mydata/[0-9]*/[0-9]*/[0-9]*/*_01.json")); for (FileStatus status : statuses) { System.out.println(status.getPath().toString()); } fs.close(); } }
注意该方案依赖Hadoop AWS包,需要在pom中引入对应版本的
hadoop-aws和hadoop-common依赖,同时要保证S3的权限配置正确。
性能优化建议
- 尽量拆分更长的固定前缀传给S3的list API,减少拉取的对象数量
- 如果文件量超过10万,建议开启S3清单功能,定期导出全量对象列表做查询,比每次实时list性能高很多
内容的提问来源于stack exchange,提问作者coolguy2021
相关产品推荐
相关产品推荐

