Java를 사용하여 지정된 S3 버킷에 지정된 키가 있는지 확인하는 방법


87

Java를 사용하여 주어진 버킷에 키가 있는지 확인하고 싶습니다. API를 살펴 봤지만 유용한 방법이 없습니다. 사용하려고했지만 getObject예외가 발생했습니다.


2
앞으로 어떤 예외가 있었는지 등 더 많은 정보를 제공해주세요 .. 가정에 따라 답변을 제공했습니다.
sethu

4
참고 :이 질문의 경우 허용 된 답변이 베스트 답변이 아닙니다.
malana 2016-06-26

답변:


3

jets3t 라이브러리를 사용하십시오. AWS SDK보다 훨씬 쉽고 강력합니다. 이 라이브러리를 사용하여 s3service.getObjectDetails ()를 호출 할 수 있습니다. 이것은 개체의 내용이 아닌 개체의 세부 정보 만 확인하고 검색합니다. 객체가 없으면 404가 발생합니다. 따라서 해당 예외를 포착하고 앱에서 처리 할 수 ​​있습니다.

그러나 이것이 작동하려면 해당 버킷의 사용자에 대한 ListBucket 액세스 권한이 있어야합니다. GetObject 액세스 만 작동하지 않습니다. 그 이유는 Amazon이 ListBucket 액세스 권한이없는 경우 키가 있는지 확인하지 못하도록하기 때문입니다. 키가 있는지 여부를 아는 것만으로도 어떤 경우에는 악의적 인 사용자에게도 충분합니다. 따라서 ListBucket 액세스 권한이 없으면 그렇게 할 수 없습니다.


4
모두-
아래이

3
jets3t는 더 이상 사용되지 않는 오래된 라이브러리입니다. 대신 aws-java-sdk를 사용하십시오.
the_storyteller 20:49에

"더 쉽고 강력 함"은 매우 주관적입니다
Leo Romanovsky

291

이제 공식 Java API에 doesObjectExist 메소드가 있습니다.

즐겨!


13
그것은 1.10.51에 추가되었습니다
steamer25

4
우리는 이것을 찬성하고 이것을 정상에 올려야합니다!
SureshS

2
해야 할 옳은 일은 이것을 받아 들인 대답으로 만드는 것이지만 OP만이 그렇게 할 수 있습니다. meta.stackexchange.com/questions/120568/...
malana

4
이것은 네트워크 호출을해야하는데, 객체가 많은 경우 비용이 많이 듭니다. 메타 데이터 요청에서 null을 반환 할 수 없습니다.
Joel

9
doesObjectExist2.x SDK (현재 v2.3.9)에서 Amazon이 제거 된 것 같습니다 .
Bampfer

59

최신 정보:

그것을 확인하는 새로운 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를 제공하지 않았다는 것입니다. 예외에 대한 문서 일뿐입니다.


14
프로그램 제어를 위해 예외 처리를 사용하지 마십시오.
Simon Peck 2013

34
@SimonPeck : 당신 말이 맞아요. 문제는 Amazon이이 흐름을 확인하는 API를 제공하지 않았다는 것입니다. 예외에 대한 문서 일뿐입니다. 찬성하지 않은 경우 반대표를 제거하십시오.
AlikElzin-kilaka 2013

1
이것은 Java SDK의 경우 더 이상 사실이 아닌 것 같습니다. my errorMessage가 "Not Found"로 설정되어 있지만 errorCode이 null입니다.
bstempi

3
나는 상태 코드를 찾고 갈 것 (404) 문자열을보고보다 더 강력한 보인다
오스카 Kjellin

2
@rboarman의 댓글이 잘못되었습니다 NoSuchKey. S3 오류 코드의 최종 목록은 다음 문서를 참조하십시오. docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
Allen George

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을 throw하는데 두 번 호출하는 이유는 무엇입니까? 또한이 예외에서 개체가 존재하지 않는다는 것을 어떻게 알 수 있습니까? 아마도 다른 S3 오류 때문일 수 있으며 실제로 객체가 발견되었습니다.
AlikElzin-kilaka

5
프로그램 제어를 위해 예외 처리를 사용하지 마십시오.
Simon Peck 2013

4
@ AlikElzin-kilaka, 왜냐하면 getObject ()는 객체의 내용을 다운로드해야한다는 것을 의미하기 때문입니다.
Jason Nichols

18
@SimonPeck, 이상적이지는 않지만 Amazon이 적절한 exists () 메소드를 제공하면 포인트가 유효합니다.
Jason Nichols

4
@SimonPeck이 경우 대안이 있습니까? 이것은 프로그램 제어 흐름으로서 예외를 노골적으로 남용하는 것이 아닙니다. 이것은 간단하고 정확하며 안전합니다. 아이디어를 극단적으로 취한다면 (이 코드 스 니펫이 예외를 남용한다고 생각한다면 분명히 그렇듯이), 왜 언어에 예외가 있습니까? 프로그램에 경고하고 프로그램의 흐름을 변경하기 위해 예외 던지는 대신 런타임이 종료되어야한다고 생각합니다.
Don Cheadle 2015 년

17

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()적절한 문자열을 사용 하고 확인할 수 있습니다 (버전에 따라 다름).


s3 객체에 메타 데이터가 연결되어 있지 않으면 s3 객체가 존재하더라도 getObjectMetadata에서 404 오류가 발생합니다. 목표가 s3 객체의 존재를 확인하는 것이라면 이것을 권장하지 않습니다.
Ashish Goel

@AshishGoel, 개체가 있으면 항상 메타 데이터가 있습니다. 실제로 기본 HTTP 요청은 객체의 URL에 대한 HEAD입니다.
Paul Draper

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

7
경고! 아마존은 각 LIST 호출에 대해 추가 요금을 부과합니다! 이 방법은 괜찮지 만 다운로드하기 전에 파일이 있는지 확인하는 데 사용하지 마십시오.
user34402

접두사와 일치하는 모든 개체를 가져 오므로 파일이 존재하는지 확인하는 좋은 방법이 아닙니다. 키로 시작하는 여러 파일이있는 경우 지정한 파일을 포함하여 모든 개체를 다운로드합니다.
Crypth

LIST 대 GET 비용 관련 : 전송 된 데이터에 대해서도 요금이 부과됩니다. 따라서 파일이 존재할 가능성 이 극히 낮 으면 (예 : 임의의 UUID를 키로 생성하고 이미 사용 중이 아닌지 확인하려는 경우) GET이 훨씬 저렴합니다. 그러나 파일이 0.5MB이고 이미 존재할 확률이 11 % 인 경우 LIST가 조금 더 저렴 해 보입니다. 파일이 0.1MB이고 기존 가능성이 52 % 인 경우에도 동일합니다. 파일이 클수록 LIST가 더 저렴 해집니다. 그러나 일반적인 시나리오는 새로 생성 된 UUID 키를 테스트하는 것이며 GET이 더 저렴합니다.
Bampfer

5

PHP의 경우 (질문이 Java라는 것을 알고 있지만 Google이 여기로 가져 왔습니다) 스트림 래퍼 및 file_exists를 사용할 수 있습니다.

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

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

2
이것은 작동하지만 수천 개 또는 파일이 있고 각 파일 루프가 필요한 경우에도 느려질 것입니다.
Danijel 2014

@Danijel이 말했듯이 이것은 실제로 주어진 키의 객체가 존재하는지 여부를 결정하지만 그렇게하려면 존재 여부를 결정하기 전에 S3에서 잠재적으로 수만 개의 객체를 반복해야 합니다
Don Cheadle

1
@Danijel과 mmcrae가 느리다는 점에 동의하지 않습니다. listObjects 요청은 .withPrefix (file)을 지정하므로 이름이 대상 파일의 이름으로 시작하는 다른 파일이없는 경우 일치하는 단일 파일 만 반환해야합니다.
davidwebster48

3

길을 양동이와 물건으로 나누십시오. 메소드를 사용하여 버킷 doesBucketExist테스트, 목록 크기를 사용하여 객체 테스트 (존재하지 않는 경우 0). 따라서이 코드는 다음을 수행합니다.

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

쉽고 간단합니다. 감사합니다
Thermech

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

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

        }

후드 + 예외 캐치에서 동일한 get-metadata 호출을 수행합니다. grepcode.com/file/repo1.maven.org/maven2/net.java.dev.jets3t/…
alexandroid

1

다른 답변은 AWS SDK v1에 대한 것입니다. 다음은 AWS SDK v2 (현재 2.3.9)에 대한 방법입니다.

getObjectMetadatadoesObjectExistv2와의 SDK에서 현재 사용하지 않는 방법! 그래서 그것들은 더 이상 옵션이 아닙니다. getObject또는 을 사용해야합니다 listObjects.

listObjects현재 통화 비용은 getObject. 하지만 AWS는 다운로드 한 데이터에 대해서도 요금을 부과 getObject 하므로 파일이 존재 하는 경우 가격이 올라 갑니다. 파일이 존재하지 않을 가능성이 매우 낮은 한 (예 : 새 UUID 키를 무작위로 생성하고 가져 오지 않았는지 다시 확인해야 함) getObject내 계산에서 호출 비용이 훨씬 저렴합니다.

안전 range()을 위해 AWS에 파일의 몇 바이트 만 보내도록 요청 하는 사양을 추가했습니다 . 내가 아는 한 SDK는 항상 이것을 존중하고 전체 파일 다운로드에 대해 비용을 청구하지 않습니다. 그러나 나는 당신 자신의 책임하에 그 행동에 의존한다는 것을 확인하지 않았습니다! (또한 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선언되고 다른 곳에서 초기화됩니다. 메서드는 부울을 반환하지만 예외를 throw 할 수 있습니다.


같아 지금 거기 있어요 s3Client.headObject(): V2에서이해야 할 일 stackoverflow.com/a/56949742/9814131을 , 당신은 확인합니다 S3Exception개체가 GitHub의 발행에 따라 존재하는지 확인의 상태 코드 (404)를 github.com/aws/aws-sdk- java-v2 / issues / 297 . 그러나 0-3 바이트만큼 오버 헤드가 거의 없기 때문에 더 진보적이라고 생각합니다.
Shaung Cheng


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로 업데이트하고 위에서 말한 것처럼 doesObjectExist를 사용합니다.


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

던졌습니다 NoSuchKeyException
Andrii Karaivanskyi

키가 존재하지 않기 때문입니다. 그것이 바로 당신이 찾고있는 것입니다. 따라서 해당 예외를 처리하고 false를 반환하십시오. try / catch를 포함하도록 위의 코드를 업데이트했습니다.
Navigatron

그러면 전혀 필요하지 않습니다 headObjectResponse. throws Exception또한 필요하지 않습니다.
Andrii Karaivanskyi

@AndriiKaraivanskyi는 단지 예일 뿐이며 테스트하지 않았습니다.
Navigatron

headObjectResponse.sdkHttpResponse (). isSuccessful (); 파일이 있는지 여부에 관계없이 항상 성공합니까?
마크

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;


공용 클래스 GetObject {
  public static void main (String [] args)
    Throws NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException {
    // 참고 : YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY 및 my-bucketname은
    // 더미 값, 원래 값으로 대체하십시오.
    // s3 끝점 설정, 지역 자동 계산
    MinioClient s3Client = new MinioClient ( "https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY");
    InputStream stream = s3Client.getObject ( "my-bucketname", "my-objectname");

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

    stream.close ();
  }
}

도움이되기를 바랍니다.

면책 조항 : 나는 Minio에서 일합니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.