C# ASP.NET中获取AWS S3存储桶指定文件夹子文件夹列表问题
问题描述
初始问题
我有一个用来获取AWS S3存储桶指定文件夹下所有子文件夹列表的方法:
public static async Task<List<string>> GetAvailableDatasetsList(AmazonS3Client s3Client, string bucketName) { try { ListObjectsV2Response response = await s3Client.ListObjectsV2Async(new ListObjectsV2Request { BucketName = bucketName, Prefix = "folderName1", StartAfter = "folderName1" }); Console.WriteLine($"Size: {response.S3Objects.Count}"); return response.S3Objects .Select(o => o.Key.Split('/')[1]) .Distinct() .ToList(); } catch (AmazonS3Exception e) { Console.WriteLine("Error retrieving list from S3: " + e.Message); return null; } catch (Exception e) { Console.WriteLine("Error: " + e.Message); return null; } }
我的S3存储桶结构如下:
bucketName - folderName1 - subfolder1 - *该文件夹下有超过1000个文件[图片] - subfolder2 - *该文件夹下有超过1000个文件[图片] - subfolder3 - *该文件夹下有超过1000个文件[图片]
我期望返回的列表是:
subFolder1 subFolder2 subFolder3
但当前方法只返回subFolder2,response.S3Objects.Count显示为1000,最终返回的列表长度仅为1,求修复方法。
更新后的问题
我通过分页实现了预期输出,但现在出现子文件夹被重复添加到列表的问题,更新后的方法如下:
public static async Task<List<string>> GetAvailableDatasetsList(AmazonS3Client s3Client, string bucketName) { try { List<string> customUploads = new List<string>(); string continuationToken = null; do { ListObjectsV2Response response = await s3Client.ListObjectsV2Async(new ListObjectsV2Request { BucketName = bucketName, Prefix = "custom-uploads", StartAfter = "custom-uploads", ContinuationToken = continuationToken }); customUploads.AddRange(response.S3Objects .Select(o => o.Key.Split('/')[1]) .Distinct()); continuationToken = response.NextContinuationToken; } while (continuationToken != null); return customUploads; } catch (AmazonS3Exception e) { Console.WriteLine("Error retrieving list from S3: " + e.Message); return null; } catch (Exception e) { Console.WriteLine("Error: " + e.Message); return null; } }
解决方案
初始问题根因
S3的ListObjectsV2接口默认单次最多返回1000条结果,你的每个子文件夹下都有超过1000个文件,单次调用只能拿到某一个子文件夹的全部文件,因此只能返回一个子文件夹名称。要获取所有子文件夹,必须分页遍历所有对象,或者用更高效的方式直接获取子目录。
优化方案一:用分隔符直接获取子文件夹(推荐)
利用S3的Delimiter参数,不需要遍历所有文件就能直接拿到指定目录下的直接子文件夹,性能大幅提升:
public static async Task<List<string>> GetAvailableDatasetsList(AmazonS3Client s3Client, string bucketName) { try { List<string> subFolders = new List<string>(); string continuationToken = null; do { var request = new ListObjectsV2Request { BucketName = bucketName, Prefix = "folderName1/", // 注意加末尾斜杠,确保只匹配目标目录下的直接子项 Delimiter = "/", ContinuationToken = continuationToken }; var response = await s3Client.ListObjectsV2Async(request); // 从CommonPrefixes提取子文件夹名称 subFolders.AddRange(response.CommonPrefixes .Select(p => p.TrimEnd('/').Split('/').Last())); continuationToken = response.NextContinuationToken; } while (continuationToken != null); return subFolders.Distinct().ToList(); } catch (AmazonS3Exception e) { Console.WriteLine("从S3获取列表出错: " + e.Message); return null; } catch (Exception e) { Console.WriteLine("出错: " + e.Message); return null; } }
优化方案二:修复分页重复问题
如果坚持遍历所有文件,改用HashSet自动去重,避免分页时重复添加:
public static async Task<List<string>> GetAvailableDatasetsList(AmazonS3Client s3Client, string bucketName) { try { HashSet<string> customUploads = new HashSet<string>(); // HashSet自动去重 string continuationToken = null; do { ListObjectsV2Response response = await s3Client.ListObjectsV2Async(new ListObjectsV2Request { BucketName = bucketName, Prefix = "custom-uploads/", // 建议加末尾斜杠 StartAfter = "custom-uploads/", ContinuationToken = continuationToken }); foreach (var obj in response.S3Objects) { var parts = obj.Key.Split('/'); if (parts.Length >= 2) // 防止Key格式异常 { customUploads.Add(parts[1]); } } continuationToken = response.NextContinuationToken; } while (continuationToken != null); return customUploads.ToList(); } catch (AmazonS3Exception e) { Console.WriteLine("从S3获取列表出错: " + e.Message); return null; } catch (Exception e) { Console.WriteLine("出错: " + e.Message); return null; } }
关键注意点
- Prefix末尾的斜杠:必须加上
/(比如folderName1/),否则会匹配到类似folderName1abc这样的目录或文件,导致结果错误。 - Delimiter的作用:设置为
/时,S3会返回所有以Prefix开头、下一个/之前的路径,直接拿到子文件夹,无需遍历海量文件。 - HashSet去重:相比每次分页局部去重再添加到列表,用HashSet可以在添加时自动去重,避免重复项。
内容的提问来源于stack exchange,提问作者Renan
相关产品推荐
相关产品推荐

