我想使用 Java 检查给定存储桶中是否存在密钥。我查看了 API,但没有任何有用的方法。我尝试使用getObject
,但它引发了异常。
16 回答
现在在官方 Java API 中有一个doesObjectExist方法。
享受!
更新:
似乎有一个新的 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);
}
关于异常的注意事项:我知道异常不应该用于流量控制。问题是亚马逊没有提供任何 api 来检查这个流程——只是关于异常的文档。
使用 AWS 开发工具包使用 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;
}
在 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()
并检查适当的字符串(取决于版本)。
在 SDK V2 中执行此操作的正确方法是使用S3Client.headObject ,而无需实际获取对象。由AWS 更改日志正式支持。
示例代码:
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;
}
}
对于 PHP(我知道问题是 Java,但 Google 把我带到了这里),您可以使用流包装器和 file_exists
$bucket = "MyBucket";
$key = "MyKey";
$s3 = Aws\S3\S3Client->factory([...]);
$s3->registerStreamWrapper();
$keyExists = file_exists("s3://$bucket/$key");
使用 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;
}
}
}.
此 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;
}
将您的路径分成存储桶和对象。使用方法测试bucket doesBucketExist
,使用listing的大小测试对象(0表示不存在)。所以这段代码会做:
String bucket = ...;
String objectInBucket = ...;
AmazonS3 s3 = new AmazonS3Client(...);
return s3.doesBucketExist(bucket)
&& !s3.listObjects(bucket, objectInBucket).getObjectSummaries().isEmpty();
其他答案适用于 AWS SDK v1。这是 AWS SDK v2(当前为 2.3.9)的一种方法。
请注意,getObjectMetadata
和doesObjectExist
方法目前不在 v2 SDK 中!所以这些不再是选择。我们被迫使用getObject
or listObjects
。
listObjects
目前拨打电话的成本是getObject
. 但是 AWS 也会对下载的任何数据收费,这提高了getObject
文件是否存在的价格。只要文件不太可能存在(例如,您随机生成了一个新的 UUID 密钥,只需要仔细检查它是否未被占用),那么getObject
根据我的计算,调用的成本就会大大降低。
不过为了安全起见,我添加了一个range()
规范,要求 AWS 只发送文件的几个字节。据我所知,SDK 将始终尊重这一点,并且不会向您收取下载整个文件的费用。但我还没有证实这一点,所以依赖这种行为需要您自担风险!range
(另外,如果 S3 对象的长度为 0 字节,我不确定会有什么表现。)
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;
}
}
注意:此代码假定s3Client
并log
在其他地方声明和初始化。方法返回一个布尔值,但可以抛出异常。
正如其他人所提到的,对于 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;
}
}
使用对象列表。用于检查 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;
}
使用 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
}
我在使用的时候也遇到了这个问题
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,如上所述
使用 jets3t 库。它比 AWS sdk 更容易和更强大。使用这个库,您可以调用 s3service.getObjectDetails()。这将只检查和检索对象的对象的详细信息(而不是内容)。如果对象丢失,它将抛出 404。因此,您可以捕获该异常并在您的应用程序中处理它。
但为了使其正常工作,您需要对该存储桶上的用户具有 ListBucket 访问权限。只是 GetObject 访问将不起作用。原因是,如果您没有 ListBucket 访问权限,亚马逊将阻止您检查密钥是否存在。在某些情况下,仅知道密钥是否存在对于恶意用户也足够了。因此,除非他们拥有 ListBucket 访问权限,否则他们将无法这样做。
或者,您可以使用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工作