AWS SDK for Java版本2 - 删除S3“文件夹”或删除多个S3对象

4
我正在寻找使用AWS SDK for Java版本2删除S3 文件夹的方法。我只能找到AWS SDK版本1的示例。
我知道S3是一个对象存储,不存在文件夹的概念。我的意思是:
  • 列出具有给定前缀的给定存储桶的S3对象
  • 使用DeleteObjectsRequest删除返回的对象,以便在向AWS API发出单个HTTP调用时能够删除多达1000个对象
当我搜索示例时,我经常回到这个页面:https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingMultipleObjectsUsingJava.html,其中似乎使用的是AWS SDK for Java版本1。至少在我的电脑上,我导入了AWS SDK 2,不能像这个示例中所示直接实例化DeleteObjectsRequest。我被迫使用构建器,然后找不到相同的方法来指定要删除的密钥列表。
3个回答

5
我用下面的代码成功解决了问题。但是我觉得这种方式有点麻烦,还是希望向社区确认这样做是否正确。我尤其觉得将S3Object集合转换为ObjectIdentifier集合并且需要使用多层构建器很麻烦。为什么DeleteObjectsRequest构建器不直接允许指定一个字符串集合,表示要删除的对象的键值呢?
public static void deleteS3Objects(String bucket, String prefix) {
    ListObjectsV2Request request = ListObjectsV2Request.builder().bucket(bucket).prefix(prefix).build();
    ListObjectsV2Iterable list = s3Client.listObjectsV2Paginator(request);
    for (ListObjectsV2Response response : list) {
        List<S3Object> objects = response.contents();
        List<ObjectIdentifier> objectIdentifiers = objects.stream().map(o -> ObjectIdentifier.builder().key(o.key()).build()).collect(Collectors.toList());
        DeleteObjectsRequest deleteObjectsRequest = DeleteObjectsRequest.builder().bucket(bucket).delete(Delete.builder().objects(objectIdentifiers).build()).build();
        s3Client.deleteObjects(deleteObjectsRequest);
    }
}

这个版本没有处理文件夹已经存在的情况,请看下面我的版本。 - Bob
1
@Jasper Citi:上面的代码将为每批1000个对象发送1个请求。例如要删除1200个对象,它将发送2个请求。每个DeleteObjectsRequest可以在1个请求中删除最多1000个对象。 - Comencau
1
@Comencau 对不起,我意识到你是正确的。我找到了这份文件,证实了这一点:https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html。 - Jasper Citi
@Jasper Citi:谢谢。我本来想回复的,但是懒得动手了。也许令人困惑的是,循环ListObjectsV2Response实际上是在批处理1000个项目。然后这些项目被添加到一个且唯一的DeleteObjectsRequest中,该请求将在单个API调用中删除1000个对象。顺便说一句,Bob下面的解决方案如果有超过1000个对象,将会遇到错误,因为他把所有东西(可能超过1000个对象)都放在一个单独的DeleteObjectsRequest中。 - Comencau

2

这是对 @Comencau 老师有用回答的改进,它处理了未找到对象的情况: MalformedXML: 您提供的 XML 不符合格式或者未通过我们发布的模式验证

public static void deleteS3Data(String bucket, String prefix) {
    S3Client s3Client = S3Client.builder().region(region).build();
    ListObjectsV2Request request = ListObjectsV2Request.builder().bucket(bucket).prefix(prefix).build();
    ListObjectsV2Iterable list = s3Client.listObjectsV2Paginator(request);

    List<ObjectIdentifier> objectIdentifiers = list
            .stream()
            .flatMap(r -> r.contents().stream())
            .map(o -> ObjectIdentifier.builder().key(o.key()).build())
            .collect(Collectors.toList());

    if (objectIdentifiers.isEmpty()) return;
    DeleteObjectsRequest deleteObjectsRequest = DeleteObjectsRequest
            .builder()
            .bucket(bucket)
            .delete(Delete.builder().objects(objectIdentifiers).build())
            .build();
    s3Client.deleteObjects(deleteObjectsRequest);
}

检查零对象的观点很好,但是这个解决方案只适用于删除少于1000个对象的情况。不幸的是,AWS有每个请求1000个对象的限制,如文档所述:https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html - Jasper Citi
你需要使用循环和多个“DeleteObjectsRequest”,而不是使用“flatMap”,就像原始答案中所示。 - wilmol

0

结合现有答案; 它同时考虑了“无对象”和“1000个键限制”。

  void deleteFolder(String bucket, String prefix) {
    ListObjectsV2Request listRequest =
        ListObjectsV2Request.builder()
            .bucket(bucket)
            .prefix(prefix)
            .build();
    ListObjectsV2Iterable paginatedListResponse = s3Client.listObjectsV2Paginator(listRequest);

    for (ListObjectsV2Response listResponse : paginatedListResponse) {
      List<ObjectIdentifier> objects =
          listResponse.contents().stream()
              .map(s3Object -> ObjectIdentifier.builder().key(s3Object.key()).build())
              .toList();
      if (objects.isEmpty()) {
        break;
      }
      DeleteObjectsRequest deleteRequest =
          DeleteObjectsRequest.builder()
              .bucket(bucket)
              .delete(Delete.builder().objects(objects).build())
              .build();
      s3Client.deleteObjects(deleteRequest);
    }
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接