非线程安全版
import com.amazonaws.annotation.NotThreadSafe;import com.amazonaws.services.s3.AmazonS3;import com.amazonaws.services.s3.model.*;import java.util.*;@NotThreadSafepublic class S3ObjectsScanner implements Iterable<String> { private final static int DEFAULT_MAX_KEYS = 1000; /** * S3客户端对象 */ private AmazonS3 client; /** * 桶名 */ private String bucketName; /** * 起始索引 */ private String startPrefix; /** * 终止索引 */ private String endPrefix; /** * key的最大缓存个数 */ private int maxKeys; public S3ObjectsScanner() { this.maxKeys = DEFAULT_MAX_KEYS; } public S3ObjectsScanner(AmazonS3 client, String bucketName) { this(); this.client = client; this.bucketName = bucketName; } @NotThreadSafe private class Itr implements Iterator<String> { private final ListObjectsV2Request request; private final Queue<String> queue; private final String endPrefix; private boolean lastPage = false; Itr() { this.endPrefix = S3ObjectsScanner.this.endPrefix; request = new ListObjectsV2Request() .withBucketName(bucketName) .withStartAfter(startPrefix) .withMaxKeys(maxKeys); queue = new ArrayDeque<>(maxKeys); } @Override public synchronized boolean hasNext() { if (queue.isEmpty() && !lastPage) { loadMore(); } return !queue.isEmpty(); } @Override public synchronized String next() { if (!hasNext()) { throw new NoSuchElementException(); } return queue.poll(); } private void loadMore() { // 发送请求 ListObjectsV2Result result = client.listObjectsV2(request); // 准备下一次请求 prepareNextReq(result); // 提取Keys extraKeys(result.getObjectSummaries()); } private void prepareNextReq(ListObjectsV2Result result) { // 检查是否还有剩余数据 if (result.isTruncated()) { request.setContinuationToken(result.getNextContinuationToken()); } else { // 没有剩余数据,置位 lastPage = true; } } private void extraKeys(List<S3ObjectSummary> summaries) { for (S3ObjectSummary summary : summaries) { String key = summary.getKey(); // 检查是否到达结束的位置 if (isOver(key)) { // 结束,标志位置位,结束循环 lastPage = true; return; } // 未结束,入队 queue.offer(key); } } private boolean isOver(String key) { // 如果没有指定“终止前缀”,无论什么key都不算结束 if (endPrefix == null) { return false; } // 如果key小于“终止前缀”,也不算结束 if (endPrefix.compareTo(key) > 0) { return false; } return true; } } @Override public Iterator<String> iterator() { return new Itr(); } public AmazonS3 getClient() { return client; } public S3ObjectsScanner withClient(AmazonS3 client) { this.client = client; return this; } public String getBucketName() { return bucketName; } public S3ObjectsScanner withBucketName(String bucketName) { this.bucketName = bucketName; return this; } public String getStartPrefix() { return startPrefix; } public S3ObjectsScanner withStartPrefix(String startPrefix) { this.startPrefix = startPrefix; return this; } public String getEndPrefix() { return endPrefix; } public S3ObjectsScanner withEndPrefix(String endPrefix) { this.endPrefix = endPrefix; return this; } public int getMaxKeys() { return maxKeys; } public S3ObjectsScanner withMaxKeys(int maxKeys) { this.maxKeys = maxKeys; return this; }}