如何使用 Java 检查指定的键是否存在于给定的 S3桶中

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

189775 次浏览

使用 jets3t 库。它比 AWS sdk 简单和健壮得多。使用这个库,您可以调用 s3service.getObjectDetails ()。这将只检查和检索对象的详细信息(而不是内容)。如果物体丢失,它会抛出一个404。因此,您可以捕获这个异常并在应用程序中处理它。

但是为了让这个工作起作用,您需要让那个 bucket 上的用户访问 ListBucket。仅仅获取对象访问将不起作用。原因是,如果您没有 ListBucket 访问权限,Amazon 将阻止您检查密钥的存在。在某些情况下,只要知道密钥是否存在,对于恶意用户来说就足够了。因此,除非他们有 ListBucket 访问权限,否则他们将无法这样做。

使用 AWS SDK 使用 getObjectMetadata 方法。

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

更新:

似乎有一个新的 API 来检查这一点。请参阅本页的另一个答案: https://stackoverflow.com/a/36653034/435605

原文:

使用 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);
}

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

使用 ListObjectsRequest 设置前缀作为键。

. 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;
}
}
}.

这段 java 代码检查键(文件)是否存在于 s3 bucket 中。

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;
}

对于 PHP (我知道问题在于 Java,但是 Google 把我带到了这里) ,您可以使用流包装器和 file _ vis

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

有一种简单的方法可以使用 jetS3tAPI 的 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


}

在 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();
ObjectMetadata 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()并检查适当的字符串(取决于版本)。

把你的路分成水桶和物体。 采用 doesBucketExist方法对水桶进行测试, 使用清单的大小测试对象(如果不存在,则为0)。 所以这个代码可以:

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

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

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;
}

现在在官方 JavaAPI 中有一个 DoesObjectExist方法。

好好享受吧!

或者,您可以使用 小爪哇客户端库、其开放源码和兼容 AWS S3 API。

您可以使用 Minio-JavaStatObject.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();
}
}

I hope it helps.

免责声明: 我为 米尼奥工作

下面是 AWS SDK v2(目前为2.3.9)的一个方法。

请注意,getObjectMetadatadoesObjectExist方法目前不在 v2 SDK 中!所以这些都不再是选择了。我们被迫使用 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。方法返回一个布尔值,但是可以抛出异常。

The right way to do it in SDK V2, without the overload of actually getting the object, 就是使用 S3Client.headObjectAWS 更改日志的官方支持。

示例代码:

public boolean exists(String bucket, String key) {
try {
HeadObjectResponse headResponse = client
.headObject(HeadObjectRequest.builder().bucket(bucket).key(key).build());
return true;
} catch (NoSuchKeyException e) {
return false;
}
}

正如其他人提到的,对于 AWS S3 Java SDK 2.10 + ,您可以使用 头部目标请求对象来检查您的 S3 bucket 中是否有文件。这将作为一个 GET 请求,而不实际获取文件。

Example code since others haven't actually added any code above:

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;
}
}

我也遇到了这个问题 当我吸毒的时候

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,并使用 doesObjectExist 如上所述