如何使用Java检查给定S3存储桶中是否存在指定的密钥

时间:2011-11-28 22:04:59

标签: java amazon-web-services amazon-s3 aws-sdk

我想检查使用Java在给定存储桶中是否存在密钥。我查看了API,但没有任何方法有用。我尝试使用getObject,但它抛出异常。

16 个答案:

答案 0 :(得分:225)

现在官方Java API中有doesObjectExist方法。

享受!

答案 1 :(得分:55)

使用errorCode.equals("NoSuchKey")

try {
    AmazonS3 s3 = new AmazonS3Client(new ClasspathPropertiesFileCredentialsProvider());
    String bucketName = getBucketName();
    s3.createBucket(bucketName);
    S3Object object = s3.getObject(bucketName, getKey());
} catch (AmazonServiceException e) {
    String errorCode = e.getErrorCode();
    if (!errorCode.equals("NoSuchKey")) {
        throw e;
    }
    Logger.getLogger(getClass()).debug("No such key!!!", e);
}

注意异常:我知道异常不应该用于流控制。问题是亚马逊没有提供任何api来检查这个流程 - 只是关于异常的文档。

答案 2 :(得分:21)

使用AWS SDK使用getObjectMetadata方法。如果密钥不存在,该方法将抛出AmazonServiceException。

private AmazonS3 s3;
...
public boolean exists(String path, String name) {
    try {
        s3.getObjectMetadata(bucket, getS3Path(path) + name); 
    } catch(AmazonServiceException e) {
        return false;
    }
    return true;
}

答案 3 :(得分:11)

在Amazon Java SDK 1.10+中,您可以使用getStatusCode()获取HTTP响应的状态代码,如果该对象不存在,则为404。

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import org.apache.http.HttpStatus;

try {
    AmazonS3 s3 = new AmazonS3Client();
    S3Object object = s3.getObjectMetadata("my-bucket", "my-client");
} catch (AmazonS3Exception e) {
    if (e.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
        // bucket/key does not exist 
    } else {
        throw e;
    }
}

getObjectMetadata()消耗的资源更少,而且不需要像getObject()那样关闭响应。

在以前的版本中,您可以使用getErrorCode()并检查相应的字符串(取决于版本)。

答案 4 :(得分:6)

使用jets3t库。它比AWS sdk更容易和更强大。使用此库可以调用s3service.getObjectDetails()。这将仅检查和检索对象的对象(而不是内容)的详细信息。如果对象丢失,它将抛出404。因此,您可以捕获该异常并在您的应用中处理它。

但为了使其正常工作,您需要为该存储桶上的用户提供ListBucket访问权限。只是GetObject访问将无法正常工作。原因是,如果您没有ListBucket访问权限,亚马逊将阻止您检查是否存在密钥。在某些情况下,仅知道密钥是否存在,对于恶意用户也是足够的。因此,除非他们有ListBucket访问权限,否则他们将无法访问。

答案 5 :(得分:5)

使用ListObjectsRequest设置Prefix作为密钥。

.NET代码:

 public bool Exists(string key)
    {

        using (Amazon.S3.AmazonS3Client client = (Amazon.S3.AmazonS3Client)Amazon.AWSClientFactory.CreateAmazonS3Client(m_accessKey, m_accessSecret))
        {
            ListObjectsRequest request = new ListObjectsRequest();
            request.BucketName = m_bucketName;
            request.Prefix = key;
            using (ListObjectsResponse response = client.ListObjects(request))
            {

                foreach (S3Object o in response.S3Objects)
                {
                    if( o.Key == key )
                        return true;
                }
                return false;
            }
        }
    }.

答案 6 :(得分:5)

对于PHP(我知道问题是Java,但谷歌把我带到这里),你可以使用流包装器和file_exists

$bucket = "MyBucket";
$key = "MyKey";
$s3 = Aws\S3\S3Client->factory([...]);
$s3->registerStreamWrapper();
$keyExists = file_exists("s3://$bucket/$key");

答案 7 :(得分:4)

此java代码检查s3存储桶中是否存在密钥(文件)。

public static boolean isExistS3(String accessKey, String secretKey, String bucketName, String file) {

    // Amazon-s3 credentials
    AWSCredentials myCredentials = new BasicAWSCredentials(accessKey, secretKey); 
    AmazonS3Client s3Client = new AmazonS3Client(myCredentials); 

    ObjectListing objects = s3Client.listObjects(new ListObjectsRequest().withBucketName(bucketName).withPrefix(file));

    for (S3ObjectSummary objectSummary: objects.getObjectSummaries()) {
        if (objectSummary.getKey().equals(file)) {
            return true;
        }
    }
    return false;
}

答案 8 :(得分:3)

使用Object isting。用于检查AWS S3中是否存在指定密钥的Java函数。

boolean isExist(String key)
    {
        ObjectListing objects = amazonS3.listObjects(new ListObjectsRequest().withBucketName(bucketName).withPrefix(key));

        for (S3ObjectSummary objectSummary : objects.getObjectSummaries())
        {
            if (objectSummary.getKey().equals(key))
            {
                return true;
            }

        }
        return false;
    }

答案 9 :(得分:2)

将你的路径分解为桶和对象。 使用doesBucketExist方法测试存储桶, 使用列表的大小测试对象(如果不存在则为0)。 所以这段代码会做:

String bucket = ...;
String objectInBucket = ...;
AmazonS3 s3 = new AmazonS3Client(...);
return s3.doesBucketExist(bucket) 
       && !s3.listObjects(bucket, objectInBucket).getObjectSummaries().isEmpty();

答案 10 :(得分:1)

使用jetS3t API的isObjectInBucket()方法可以轻松实现。

示例代码:

ProviderCredentials awsCredentials = new AWSCredentials(
                awsaccessKey,
                awsSecretAcessKey);

        // REST implementation of S3Service
        RestS3Service restService = new RestS3Service(awsCredentials);

        // check whether file exists in bucket
        if (restService.isObjectInBucket(bucket, objectKey)) {

            //your logic

        }

答案 11 :(得分:1)

就像其他人提到的那样,对于AWS S3 Java SDK 2.10+,您可以使用HeadObjectRequest对象检查S3存储桶中是否有文件。这将像一个GET请求一样,实际上并没有获取文件。

示例代码,因为其他人实际上并未在上面添加任何代码:

public boolean existsOnS3 () throws Exception {
    try {
       S3Client s3Client = S3Client.builder ().credentialsProvider (...).build ();
       HeadObjectRequest headObjectRequest = HeadObjectRequest.builder ().bucket ("my-bucket").key ("key/to/file/house.pdf").build ();
       HeadObjectResponse headObjectResponse = s3Client.headObject (headObjectRequest);
       return headObjectResponse.sdkHttpResponse ().isSuccessful ();    
   }
   catch (NoSuchKeyException e) {
      //Log exception for debugging
      return false;
   }
}

答案 12 :(得分:1)

我也遇到了这个问题 当我使用

String BaseFolder = "3patti_Logs"; 
S3Object object = s3client.getObject(bucketName, BaseFolder);
 

我找不到错误密钥

当我尝试尝试时

String BaseFolder = "3patti_Logs"; 
S3Object object = s3client.getObject(bucketName, BaseFolder+"/");

它正常工作,此代码在1.9 jar上正常工作,否则更新为1.11并使用如上所述的dosObjectExist

答案 13 :(得分:0)

或者,您可以使用Minio-Java客户端库,其开源并与AWS S3 API兼容。

您可以使用Minio-Java StatObject.java示例。

import io.minio.MinioClient;
import io.minio.errors.MinioException;

import java.io.InputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;

import org.xmlpull.v1.XmlPullParserException;


public class GetObject {
  public static void main(String[] args)
    throws NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException {
    // Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
    // dummy values, please replace them with original values.
    // Set s3 endpoint, region is calculated automatically
    MinioClient s3Client = new MinioClient("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY");
    InputStream stream = s3Client.getObject("my-bucketname", "my-objectname");

    byte[] buf = new byte[16384];
    int bytesRead;
    while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
      System.out.println(new String(buf, 0, bytesRead));
    }

    stream.close();
  }
}

我希望它有所帮助。

免责声明:我为Minio

工作

答案 14 :(得分:0)

其他答案适用于AWS开发工具包v1。这是适用于AWS开发工具包v2(当前为2.3.9)的方法。

请注意,v2 SDK当前没有getObjectMetadatadoesObjectExist方法!因此,这些不再是选择。我们被迫使用getObjectlistObjects

listObjects的呼叫当前费用是getObject的12.5倍。但是AWS还会对下载的所有数据收取费用,如果文件存在,则会提高getObject 的价格。只要文件不太可能存在(例如,您随机生成了一个新的UUID密钥,并且只需要仔细检查该文件是否被占用),那么根据我的计算,调用getObject的成本就便宜得多。

不过,出于安全考虑,我添加了一个range()规范,要求AWS仅发送文件的几个字节。据我知道的SDK将始终尊重这一点,不收你为下载整个文件。但是我还没有证实,因此依靠这种行为需要您自担风险! (此外,如果S3对象的长度为0个字节,我不确定range的行为。)

    private boolean sanityCheckNewS3Key(String bucket, String key) {

        ResponseInputStream<GetObjectResponse> resp = null;
        try {
            resp = s3client.getObject(GetObjectRequest.builder()
                .bucket(bucket)
                .key(key)
                .range("bytes=0-3")
                .build());
        }
        catch (NoSuchKeyException e) {
            return false;
        }
        catch (AwsServiceException se) {
            throw se;
        }
        finally {
            if (resp != null) {
                try {
                    resp.close();
                } catch (IOException e) {
                    log.warn("Exception while attempting to close S3 input stream", e);
                }
            }
        }
        return true;
    }
}

注意:此代码假定s3Clientlog在其他地方声明和初始化。方法返回一个布尔值,但可以引发异常。

答案 15 :(得分:0)

在SDK V2中执行此操作的正确方法,而不会导致实际获取对象的负担, 是使用S3Client.headObject。 由AWS Change Log官方支持。