जावा का उपयोग करके दिए गए S3 बाल्टी में निर्दिष्ट कुंजी मौजूद है या नहीं, इसकी जांच कैसे करें


86

मैं यह जांचना चाहूंगा कि क्या जावा का उपयोग करके किसी दिए गए बाल्टी में एक कुंजी मौजूद है। मैंने एपीआई को देखा लेकिन कोई भी तरीका उपयोगी नहीं है। मैंने उपयोग करने की कोशिश की getObjectलेकिन इसने एक अपवाद फेंक दिया।


2
भविष्य में, कृपया अधिक जानकारी प्रदान करें जैसे कि आपको क्या अपवाद मिला .. मैंने एक धारणा के आधार पर उत्तर प्रदान किया है ..
सेतु

4
FYI करें: इस प्रश्न के लिए, स्वीकृत उत्तर सबसे अच्छा उत्तर नहीं है।
मलाना

जवाबों:


3

जेट 3 टी लाइब्रेरी का उपयोग करें। यह एडब्ल्यूएस एसडीके की तुलना में बहुत अधिक आसान और मजबूत है। इस लाइब्रेरी का उपयोग करके आप कॉल कर सकते हैं, s3service.getObjectDetails ()। यह ऑब्जेक्ट के केवल विवरण (सामग्री नहीं) की जाँच करेगा और पुनः प्राप्त करेगा। यदि ऑब्जेक्ट गायब है, तो यह 404 फेंक देगा। तो आप उस अपवाद को पकड़ सकते हैं और अपने ऐप में इससे निपट सकते हैं।

लेकिन इसके लिए काम करने के लिए, आपको उस बाल्टी पर उपयोगकर्ता के लिए ListBucket एक्सेस की आवश्यकता होगी। बस GetObject पहुँच काम नहीं करेगा। कारण है, अगर आप ListBucket पहुँच नहीं है, तो Amazon आपको कुंजी की उपस्थिति के लिए जाँच करने से रोकेगा। बस यह जानना कि कोई कुंजी मौजूद है या नहीं, कुछ मामलों में दुर्भावनापूर्ण उपयोगकर्ताओं के लिए भी पर्याप्त होगा। इसलिए जब तक उनके पास ListBucket एक्सेस नहीं है, वे ऐसा करने में सक्षम नहीं होंगे।


4
सभी - नीचे दिए गए इस प्रश्न का एक अद्यतन उत्तर देखें: stackoverflow.com/a/36653034/49678
alexandroid

3
जेट्स ३ टी एक पुरानी पदावनत लाइब्रेरी है। इसके बजाय aws-java-sdk का उपयोग करें।
the_storyteller

"आसान और अधिक मजबूत" बहुत व्यक्तिपरक है
लियो रोमानोव्स्की

290

अब आधिकारिक जावा एपीआई में एक doObjectExist पद्धति है।

का आनंद लें!


13
इसे 1.10.51
स्टीमर 25

4
हमें इसे उभारना है और इसे शीर्ष पर ले जाना है!
सुरेश

2
सही बात यह है कि यह स्वीकार किए जाते हैं, लेकिन केवल ओपी ही ऐसा कर सकता है। meta.stackexchange.com/questions/120568/…
malana

4
यह एक नेटवर्क कॉल करना चाहिए, जो महंगी है यदि आपके पास बहुत सारी वस्तुएं हैं ... बहुत बुरा यह मेटाडेटा अनुरोध पर बस वापस नहीं कर सकता है।
जोएल

9
ऐसा लगता है कि अमेज़ॅन doesObjectExist2.x एसडीके (वर्तमान में v2.3.9) से हटा दिया गया है।
बामफेर

59

अपडेट करें:

ऐसा लगता है कि वहाँ एक नया एपीआई बस की जाँच करने के लिए है। इस पृष्ठ में एक और उत्तर देखें: 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);
}

अपवाद के बारे में ध्यान दें: मुझे पता है कि प्रवाह नियंत्रण के लिए अपवादों का उपयोग नहीं किया जाना चाहिए। समस्या यह है कि अमेज़ॅन ने इस प्रवाह की जांच करने के लिए कोई एपीआई प्रदान नहीं किया - केवल अपवाद के बारे में दस्तावेज।


14
प्रोग्राम नियंत्रण के लिए अपवाद हैंडलिंग का उपयोग न करें।
साइमन पेक

34
@SimonPeck: आप सही हैं। समस्या यह है कि अमेज़ॅन ने इस प्रवाह को जांचने के लिए कोई एपीआई प्रदान नहीं किया - केवल अपवाद के बारे में दस्तावेज। कृपया अपना डाउन-वोट हटा दें, यदि यह मतदान नहीं है।
एलिकएल्ज़िन-किलाका

1
यह जावा एसडीके के लिए अब और सच नहीं प्रतीत होता है। मैं देखता हूं कि मेरा errorMessage"नहीं मिला" पर सेट है, लेकिन errorCodeअशक्त है।
bstempi

3
मैं स्टेटस कोड 404 की तलाश में
जाऊंगा।

2
@Rboarman द्वारा टिप्पणी गलत है - यह है NoSuchKey। S3 त्रुटि कोड की एक निश्चित सूची के लिए, दस्तावेज़ देखें: docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
एलन

22

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

2
getObject AmazonServiceException को भी फेंकता है, तो दो कॉल क्यों करें? इसके अलावा, मुझे कैसे पता चलेगा कि वस्तु इस बहाने से मौजूद नहीं है? शायद यह एक और S3 त्रुटि के कारण था और वस्तु वास्तव में मिली है।
एलिकएल्ज़िन-किलोका

5
प्रोग्राम नियंत्रण के लिए अपवाद हैंडलिंग का उपयोग न करें।
साइमन पेक

4
@ AlikElzin-kilaka, क्योंकि getObject () का अर्थ है कि आपको ऑब्जेक्ट की सामग्री को डाउनलोड करना होगा, जो संभवतः विशाल हो सकता है।
जेसन निकोल्स

18
@SimonPeck, यह आदर्श नहीं है, लेकिन जब अमेज़न एक उचित अस्तित्व () विधि प्रदान करता है, तो आपकी बात मान्य है।
जेसन निकोल्स

4
@SimonPeck क्या आपके पास इस मामले में कोई विकल्प है? यह कार्यक्रम नियंत्रण प्रवाह के रूप में अपवादों का व्यापक दुरुपयोग नहीं है ... यह सरल, सटीक है कि यह क्या करता है, और सुरक्षित है। यदि आप अपने विचार को चरम पर ले जाते हैं (जैसा कि जाहिरा तौर पर आप हैं यदि आपको लगता है कि यह कोड स्निपेट अपवादों का दुरुपयोग कर रहा है), तो एक भाषा में अपवाद क्यों हैं? कार्यक्रम को सचेत करने और कार्यक्रम के प्रवाह को बदलने के लिए एक अपवाद को फेंकने के बजाय , रनटाइम को सिर्फ मुझे लगता है कि समाप्त करना चाहिए।
डॉन चेडल

16

अमेज़ॅन जावा एसडीके 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()उपयुक्त स्ट्रिंग (संस्करण पर निर्भर करता है) के लिए उपयोग और जांच कर सकते हैं ।


यदि आपकी s3 ऑब्जेक्ट में कोई मेटा डेटा संलग्न नहीं है, तो getObjectMetadata s4 ऑब्जेक्ट मौजूद होने पर भी 404 त्रुटि देगा। यदि s3 ऑब्जेक्ट के अस्तित्व की जांच करना उद्देश्य है तो मैं इसकी सिफारिश नहीं करूंगा।
आशीष गोयल

@ आशीषगेल, हमेशा मेटाडेटा होगा, यदि वस्तु मौजूद है। वास्तव में, अंतर्निहित HTTP अनुरोध ऑब्जेक्ट के URL के लिए केवल एक HEAD है।
पॉल ड्रेपर

5

अपनी कुंजी के रूप में 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;
            }
        }
    }.

7
चेतावनी! अमेज़ॅन प्रत्येक LIST कॉल के लिए अतिरिक्त शुल्क लेता है! यह विधि ठीक है, लेकिन यह जांचने के लिए उपयोग न करें कि क्या फ़ाइल डाउनलोड करने से पहले मौजूद है।
user34402

यह प्राप्त करने का एक अच्छा तरीका नहीं है यदि कोई फ़ाइल मौजूद है क्योंकि यह उन सभी वस्तुओं को प्राप्त करता है जो उपसर्ग से मेल खाते हैं। यदि आपके पास कई फाइलें हैं जो कुंजी से शुरू होती हैं, तो यह आपके द्वारा निर्दिष्ट सभी वस्तुओं को डाउनलोड करेगी।
क्रायपथ

LIST बनाम GET की लागत के बारे में: ध्यान दें कि आप किसी भी स्थानांतरित किए गए डेटा के लिए भी शुल्क लेते हैं। इसलिए यदि यह बहुत कम संभावना है कि फ़ाइल मौजूद है (उदाहरण के लिए, आपने एक कुंजी के रूप में एक यादृच्छिक यूयूआईडी उत्पन्न किया है और यह सुनिश्चित करना चाहते हैं कि यह पहले से उपयोग में नहीं है) तो जीईटी बहुत सस्ता है। लेकिन अगर फाइलें 0.5 एमबी हैं और पहले से मौजूद 11% संभावना है, तो लिस्ट थोड़ा सस्ता दिखता है। यदि फ़ाइलें 0.1 एमबी हैं और समान हैं, तो मौजूदा का 52% मौका है ... जितनी बड़ी फाइलें हैं, उतनी ही जल्दी LIST सस्ता हो जाता है। लेकिन फिर, एक आम परिदृश्य एक नई उत्पन्न यूयूआईडी कुंजी का परीक्षण कर रहा है, और इसके लिए जीईटी सस्ता है।
19 को बैम्फर

5

PHP के लिए (मुझे पता है कि सवाल जावा है, लेकिन Google मुझे यहां लाया है), आप स्ट्रीम रैपर और file_exists का उपयोग कर सकते हैं

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

4

यह जावा कोड यह जांचता है कि कुंजी (फाइल) 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;
}

2
यह काम करना चाहिए, लेकिन उन मामलों में भी धीमा होना चाहिए जहां हजारों या फाइलें हैं, और प्रत्येक फ़ाइल के लिए लूप की आवश्यकता होगी।
दानीजेल

जैसा कि @Danijel ने कहा, यह वास्तव में यह निर्धारित करेगा कि किसी दिए गए कुंजी की कोई वस्तु मौजूद है या नहीं, लेकिन ऐसा करने के लिए यह निर्धारित करने से पहले कि S3 में हजारों वस्तुओं के संभावित दसियों पर लूप होना चाहिए या मौजूद नहीं है
डॉन चीडल

1
मैं @Danijel और mmcrae से इस बारे में असहमत हूं कि यह धीमा है। लिस्ट ऑबजेक्ट रिक्वेस्ट .withPrefix (फाइल) को निर्दिष्ट करता है, इसलिए इसे ज्यादातर सिंगल मेलिंग फाइल पर लौटना चाहिए, जब तक कि अन्य फाइलें न हों जिनका नाम लक्ष्य फ़ाइल के नाम से शुरू होता है।
davidwebster48

3

बाल्टी और वस्तु में अपना रास्ता तोड़ो। विधि का उपयोग करके बाल्टी का doesBucketExistपरीक्षण करना, लिस्टिंग के आकार का उपयोग करके वस्तु का परीक्षण करना (0 मौजूद नहीं होने की स्थिति में)। तो यह कोड करेगा:

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

आसान और सरल। धन्यवाद
Thermech

3

ऑब्जेक्ट का उपयोग करना। जावा फ़ंक्शन यह जाँचने के लिए कि निर्दिष्ट कुंजी 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;
    }

1

जेटएस 3 टी एपीआई के आईओबजेक्ट इनबकेट () विधि का उपयोग करने का एक आसान तरीका है।

नमूना कोड:

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

        }

यह हुड + अपवाद कैच के तहत एक ही गेट
अलेक्जेंड्रोइड

1

अन्य जवाब AWS SDK v1 के लिए हैं। यहां AWS SDK v2 (वर्तमान में 2.3.9) के लिए एक विधि है।

ध्यान दें कि getObjectMetadataऔर doesObjectExistविधियाँ वर्तमान में v2 SDK में नहीं हैं! तो अब वे विकल्प नहीं हैं। हम getObjectया तो उपयोग करने के लिए मजबूर हैं याlistObjects

listObjectsवर्तमान में कॉल 12.5 गुना अधिक महंगी हैं getObject। लेकिन AWS डाउनलोड किए गए किसी भी डेटा के लिए भी शुल्क लेता है, जो getObject फ़ाइल मौजूद होने पर कीमत बढ़ाता है । जब तक फ़ाइल मौजूद होने की बहुत संभावना नहीं है (उदाहरण के लिए, आपने एक नई यूयूआईडी कुंजी को यादृच्छिक रूप से उत्पन्न किया है और बस यह जांचने की आवश्यकता है कि इसे नहीं लिया गया है) फिर कॉल करनाgetObject मेरी गणना से काफी सस्ती है।

बस सुरक्षित पक्ष पर होने के लिए, मैंने range()एडब्ल्यूएस को केवल फ़ाइल के कुछ बाइट्स भेजने के लिए कहने के लिए एक विनिर्देश जोड़ा । जहां तक ​​मुझे पता है एसडीके हमेशा इसका सम्मान करेगा और आपसे पूरी फाइल डाउनलोड करने के लिए शुल्क नहीं लेगा। लेकिन मैंने यह सत्यापित नहीं किया है कि आपके जोखिम पर उस व्यवहार पर भरोसा करें! (इसके अलावा, मुझे यकीन नहीं है कि rangeS3 ऑब्जेक्ट 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स्थिति github.com/aws/aws-sdk- के अनुसार वस्तु मौजूद है , यह जाँचने के लिए कोड 404 की जाँच करेंगे। java-v2 / मुद्दों / 297 । लेकिन मुझे लगता है कि तुम्हारा अधिक प्रगतिशील है क्योंकि यह 0-3 बाइट्स के रूप में बहुत कम ओवरहेड है।
शांग चेंग


1

जब मैंने इस्तेमाल किया तो मुझे भी इस समस्या का सामना करना पड़ा

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

मुझे त्रुटि कुंजी मिली नहीं मिली

जब मैंने मारा और कोशिश की

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

यह काम किया, यह कोड 1.9 जार के साथ काम कर रहा है अन्यथा 1.11 पर अपडेट करें और ऊपर बताए अनुसार doObjectExist का उपयोग करें


1

जैसा कि दूसरों ने उल्लेख किया है, एडब्ल्यूएस एस 3 जावा एसडीके 2.10+ के लिए आप यह जांचने के लिए हेडऑबजेक्ट रिस्पेक्ट ऑब्जेक्ट का उपयोग कर सकते हैं कि क्या आपके एस 3 बाल्टी में कोई फ़ाइल है। यह वास्तव में फ़ाइल प्राप्त किए बिना 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;
   }
}

NoSuchKeyException फेंकता है
Andrii Karaivanskyi

ऐसा इसलिए है क्योंकि कुंजी मौजूद नहीं है। यह वही है जो आप ढूंढ रहे हैं। इसलिए उस अपवाद को संभालें और इसके लिए गलत वापसी करें। मैंने कोशिश / कैच को शामिल करने के लिए उपरोक्त कोड अपडेट किया है।
नवगात्रोन

तो फिर तुम बिल्कुल जरूरत नहीं है headObjectResponsethrows Exceptionसाथ ही जरूरत नहीं है।
एंड्री करिवान्स्की

@AndriiKaraivanskyi इसका एक उदाहरण है, मैंने इसका परीक्षण नहीं किया।
नवगेट्रोन

headObjectResponse.sdkHttpResponse () .isSuccessful (); हमेशा सफल होता है कि फाइल मौजूद है या नहीं?
अंक

0

वैकल्पिक रूप से आप 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;

import org.xmlpull.v1.XmlPullParserException;


सार्वजनिक वर्ग GetObject {
  सार्वजनिक स्थैतिक शून्य main (String [] args)
    NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException {फेंकता है
    // नोट: आपका-ACCESSKEYID, आपका- SECRETACCESSKEY और my-bucketname हैं
    // डमी मान, कृपया उन्हें मूल मानों से बदलें।
    // सेट s3 समापन बिंदु, क्षेत्र की गणना स्वचालित रूप से की जाती है
    MinioClient s3Client = new MinioClient ("https://s3.amazonaws.com", "Your-ACCESSKEYID", "Your-SECRETACCESSKEY");
    InputStream स्ट्रीम = s3Client.getObject ("my-bucketname", "my-objectname");

    बाइट [] बफ = नई बाइट [16384];
    int बाइट्स रीड;
    जबकि (bytesRead = stream.read (buf, 0, buf.length))> = 0) {
      System.out.println (नया स्ट्रिंग (buf, 0, बाइट्स रीड));
    }

    stream.close ();
  }
}

मुझे उम्मीद है यह मदद करेगा।

डिस्क्लेमर: मैं मिनियो के लिए काम करता हूं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.