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)에 대한 방법입니다.

주 getObjectMetadata및 doesObjectExistv2와의 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.