ฉันต้องการตรวจสอบว่ามีคีย์อยู่ในที่เก็บข้อมูลโดยใช้ Java หรือไม่ ฉันดู API แต่ไม่มีวิธีการใดที่เป็นประโยชน์ ฉันพยายามใช้getObject
แต่มันมีข้อยกเว้น
ฉันต้องการตรวจสอบว่ามีคีย์อยู่ในที่เก็บข้อมูลโดยใช้ Java หรือไม่ ฉันดู API แต่ไม่มีวิธีการใดที่เป็นประโยชน์ ฉันพยายามใช้getObject
แต่มันมีข้อยกเว้น
คำตอบ:
ใช้ไลบรารี jets3t มันง่ายกว่าและแข็งแกร่งกว่า AWS sdk มาก การใช้ไลบรารีนี้คุณสามารถเรียก s3service.getObjectDetails () การดำเนินการนี้จะตรวจสอบและดึงเฉพาะรายละเอียดของวัตถุ (ไม่ใช่เนื้อหา) ของวัตถุ มันจะโยน 404 ถ้าวัตถุหายไป คุณจึงสามารถจับข้อยกเว้นนั้นและจัดการกับมันได้ในแอปของคุณ
แต่เพื่อให้สามารถใช้งานได้คุณจะต้องมีการเข้าถึง ListBucket สำหรับผู้ใช้ในที่เก็บข้อมูลนั้น เพียงแค่เข้าถึง GetObject จะไม่ทำงาน เหตุผลคือ Amazon จะป้องกันไม่ให้คุณตรวจสอบการมีอยู่ของคีย์หากคุณไม่มีการเข้าถึง ListBucket เพียงแค่รู้ว่ามีคีย์อยู่หรือไม่ก็เพียงพอสำหรับผู้ใช้ที่ประสงค์ร้ายในบางกรณี ดังนั้นหากพวกเขาไม่สามารถเข้าถึง ListBucket ได้พวกเขาจะไม่สามารถทำได้
ตอนนี้มีวิธีdoObjectExistใน Java API อย่างเป็นทางการ
สนุก!
doesObjectExist
จาก 2.x SDK (ปัจจุบันคือ v2.3.9)
อัปเดต:
ดูเหมือนว่าจะมี 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 ใด ๆ เพื่อตรวจสอบขั้นตอนนี้ - เป็นเพียงเอกสารเกี่ยวกับข้อยกเว้น
errorMessage
ถูกตั้งค่าเป็น "ไม่พบ" แต่errorCode
เป็นโมฆะ
NoSuchKey
มันเป็น สำหรับรายการรหัสข้อผิดพลาด S3 ที่ชัดเจนโปรดดูเอกสาร: docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
การใช้ 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;
}
ใน 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()
และตรวจสอบสตริงที่เหมาะสมได้ (ขึ้นอยู่กับเวอร์ชัน)
ใช้ 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;
}
}
}.
สำหรับ PHP (ฉันรู้ว่าคำถามคือ Java แต่ Google พาฉันมาที่นี่) คุณสามารถใช้ stream wrappers และ file_exists
$bucket = "MyBucket";
$key = "MyKey";
$s3 = Aws\S3\S3Client->factory([...]);
$s3->registerStreamWrapper();
$keyExists = file_exists("s3://$bucket/$key");
รหัส 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;
}
ทำลายเส้นทางของคุณให้เป็นถังและวัตถุ การทดสอบที่เก็บข้อมูลโดยใช้วิธีdoesBucketExist
การทดสอบวัตถุโดยใช้ขนาดของรายการ (0 ในกรณีที่ไม่มีอยู่) ดังนั้นรหัสนี้จะทำ:
String bucket = ...;
String objectInBucket = ...;
AmazonS3 s3 = new AmazonS3Client(...);
return s3.doesBucketExist(bucket)
&& !s3.listObjects(bucket, objectInBucket).getObjectSummaries().isEmpty();
การใช้ Object isting ฟังก์ชัน 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;
}
วิธีการที่เหมาะสมที่จะทำใน 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;
}
}
มีวิธีง่ายๆในการทำโดยใช้เมธอด isObjectInBucket () ของ jetS3t API
โค้ดตัวอย่าง:
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
}
คำตอบอื่น ๆ สำหรับ AWS SDK v1 นี่คือวิธีการสำหรับ AWS SDK v2 (ปัจจุบันคือ 2.3.9)
โปรดทราบว่าgetObjectMetadata
และdoesObjectExist
วิธีการไม่ได้อยู่ใน v2 SDK ในขณะนี้! ดังนั้นสิ่งเหล่านี้จึงไม่ใช่ตัวเลือกอีกต่อไป เราถูกบังคับให้ใช้อย่างใดอย่างหนึ่งgetObject
หรือlistObjects
.
listObjects
โทรขณะนี้ 12.5 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
ถูกประกาศและเริ่มต้นที่อื่น เมธอดส่งคืนบูลีน แต่สามารถโยนข้อยกเว้น
s3Client.headObject()
ใน V2 ให้ทำสิ่งนี้: stackoverflow.com/a/56949742/9814131และคุณจะตรวจสอบS3Exception
รหัสสถานะของ 404 เพื่อตรวจสอบว่ามีวัตถุอยู่ตามปัญหา github หรือไม่github.com/aws/aws-sdk- Java-v2 แต่ฉันเดาว่าของคุณมีความก้าวหน้ามากกว่าเนื่องจากมีค่าใช้จ่ายน้อยมากถึง 0-3 ไบต์
ฉันยังประสบปัญหานี้เมื่อฉันใช้
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 และใช้ doObjectExist ตามที่กล่าวไว้ข้างต้น
ดังที่คนอื่น ๆ ได้กล่าวไว้สำหรับ 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;
}
}
headObjectResponse
เลย throws Exception
ก็ไม่จำเป็นเช่นกัน
หรือคุณสามารถใช้ไลบรารีไคลเอนต์Minio-Javaซึ่งเป็นโอเพ่นซอร์สและเข้ากันได้กับ AWS S3 API
คุณสามารถใช้ตัวอย่างMinio-Java StatObject.java ได้เช่นเดียวกัน
นำเข้า io.minio.MinioClient; นำเข้า io.minio.errors.MinioException; นำเข้า java.io.InputStream; นำเข้า java.io.IOException; นำเข้า java.security.NoSuchAlgorithmException; นำเข้า java.security.InvalidKeyException; นำเข้า org.xmlpull.v1.XmlPullParserException; คลาสสาธารณะ GetObject { โมฆะคงที่สาธารณะ main (String [] args) พ่น NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException { // หมายเหตุ: Your-ACCESSKEYID, YOUR-SECRETACCESSKEY และ my-bucketname คือ // ค่าดัมมี่โปรดแทนที่ด้วยค่าดั้งเดิม // ตั้งค่าปลายทาง s3 ภูมิภาคจะถูกคำนวณโดยอัตโนมัติ MinioClient s3Client = MinioClient ใหม่ ("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); InputStream สตรีม = s3Client.getObject ("my-bucketname", "my-objectname"); ไบต์ [] buf = ไบต์ใหม่ [16384]; int ไบต์อ่าน; ในขณะที่ ((bytesRead = stream.read (buf, 0, buf.length))> = 0) { System.out.println (สตริงใหม่ (buf, 0, bytesRead)); } stream.close (); } }
ฉันหวังว่ามันจะช่วยได้
Disclaimer: ฉันทำงานให้กับMinio