web-dev-qa-db-fra.com

Comment vérifier si une clé spécifiée existe dans un compartiment S3 donné en utilisant Java

Je voudrais vérifier si une clé existe dans un compartiment donné en utilisant Java. J'ai regardé l'API mais aucune méthode n'est utile. J'ai essayé d'utiliser getObject mais cela a généré une exception.

70
in His Steps

Utilisez la bibliothèque jets3t. C'est beaucoup plus simple et robuste que le SDK AWS. En utilisant cette bibliothèque, vous pouvez appeler s3service.getObjectDetails (). Cela vérifiera et récupérera uniquement les détails de l'objet (pas le contenu) de l'objet. Il lancera un 404 si l'objet est manquant. Vous pouvez donc détecter cette exception et la traiter dans votre application.

Mais pour que cela fonctionne, vous devez disposer d'un accès ListBucket à l'utilisateur sur ce compartiment. Juste un accès GetObject ne fonctionnera pas. La raison en est, Amazon vous empêchera de vérifier la présence de la clé si vous n’avez pas accès à ListBucket. Le simple fait de savoir si une clé est présente ou non suffira également, dans certains cas, à des utilisateurs malveillants. Par conséquent, à moins d'avoir un accès ListBucket, ils ne pourront pas le faire.

7
sethu

Il existe maintenant une méthode doesObjectExist dans l'API officielle Java.

Prendre plaisir!

236
lmichelbacher

Mise à jour:

Il semble qu'il existe une nouvelle API pour vérifier cela. Voir une autre réponse dans cette page: https://stackoverflow.com/a/36653034/435605

Message original:

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

Remarque à propos de l'exception: Je sais que les exceptions ne doivent pas être utilisées pour le contrôle de flux. Le problème est qu’Amazon n’a pas fourni d’API pour vérifier ce flux, mais uniquement de la documentation sur l’exception.

56
AlikElzin-kilaka

À l'aide du kit AWS SDK, utilisez la méthode getObjectMetadata. La méthode lève une exception AmazonServiceException si la clé n'existe pas.

private AmazonS3 s3;
...
public boolean exists(String path, String name) {
    try {
        s3.getObjectMetadata(bucket, getS3Path(path) + name); 
    } catch(AmazonServiceException e) {
        return false;
    }
    return true;
}
21
user979051

Dans Amazon Java SDK 1.10+, vous pouvez utiliser getStatusCode() ) pour obtenir le code de statut de la réponse HTTP, qui sera 404 si l'objet n'existe pas.

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import org.Apache.http.HttpStatus;

try {
    AmazonS3 s3 = new AmazonS3Client();
    S3Object 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() consomme moins de ressources et la réponse n'a pas besoin d'être fermée comme getObject().


Dans les versions précédentes, vous pouvez utiliser getErrorCode() et rechercher la chaîne appropriée (dépend de la version).

11
Paul Draper

Utilisez le paramètre préfixe ListObjectsRequest comme clé.

Code .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;
            }
        }
    }.
5
user34402

Pour PHP (je sais que la question est Java, mais Google m'a amené ici)), vous pouvez utiliser des wrappers de flux et des file_exists.

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

Ce code Java) vérifie si la clé (fichier) existe dans le compartiment 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;
}
4
c0mrade

Brisez votre chemin dans un seau et un objet. Tester le compartiment en utilisant la méthode doesBucketExist, Tester l'objet en utilisant la taille de la liste (0 s'il n'existe pas). Donc ce code fera:

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

Utiliser Object isting. Java Fonction permettant de vérifier si la clé spécifiée existe dans 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;
    }
3
Kaustuv

Il existe un moyen simple de le faire en utilisant la méthode isObjectInBucket () de l'API jetS3t.

Exemple de code:

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
Dhwaneel

Les autres réponses concernent AWS SDK v1. Voici une méthode pour AWS SDK v2 (actuellement 2.3.9).

Notez que les méthodes getObjectMetadata et doesObjectExist ne sont pas actuellement dans le SDK v2! Donc, ce ne sont plus des options. Nous sommes obligés d'utiliser getObject ou listObjects.

Les appels listObjects coûtent actuellement 12,5 fois plus cher que getObject. Mais AWS facture également toutes les données téléchargées, ce qui augmente le prix de getObjectsi le fichier existe. Tant qu'il est très peu probable que le fichier existe (par exemple, vous avez généré une nouvelle clé UUID de manière aléatoire et vous devez juste vérifier qu'il n'est pas utilisé), appeler getObject est nettement moins cher, selon mon calcul. .

Juste pour être sûr, j'ai ajouté une spécification range() demandant à AWS de n'envoyer que quelques octets du fichier. Autant que je sache, le SDK respectera toujours cela et ne vous facturera pas le téléchargement du fichier entier. Mais je n'ai pas vérifié cela, alors comptez sur ce comportement à vos risques et périls! (De plus, je ne suis pas sûr de savoir comment se comporte range si l'objet S3 a une longueur de 0 octet.)

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

Remarque: ce code suppose que s3Client et log sont déclarés et initialisés ailleurs. La méthode retourne un booléen, mais peut générer des exceptions.

0
Bampfer

La bonne façon de le faire dans SDK V2, sans la surcharge d'objet, consiste à utiliser S3Client.headObject . Officiellement sauvegardé par AWS Change Log .

0
E.T

Vous pouvez également utiliser la bibliothèque client Minio-Java , son source ouverte et compatible avec l'API AWS S3.

Vous pouvez utiliser les exemples Minio-Java StatObject.Java pour les mêmes.

 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; 
 
 
 Classe publique GetObject {
 public static void main (String [] args) 
 lève les exceptions NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException {
 // Remarque: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY et my-bucketname sont 
 // valeurs factices, veuillez les remplacer par les valeurs d'origine. 
 // Définissez le point final s3, la région est calculée automatiquement 
 MinioClient s3Client = new MinioClient ("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); 
 Flux en entrée = s3Client.getObject (" my-bucketname "," mon-objectname "); 
 
 octet [] buf = ne w octet [16384]; 
 int bytesRead; 
 tant que ((bytesRead = stream.read (buf, 0, buf.length))>> 0) {
 System.out .println (nouvelle chaîne (buf, 0, bytesRead)); 
} 
 
 stream.close (); 
} 
} 

J'espère que ça aide.

Disclaimer: Je travaille pour Minio

0
koolhead17