Vorrei verificare se esiste una chiave in un determinato bucket utilizzando Java. Ho esaminato l'API ma non ci sono metodi utili. Ho provato a usare getObject
ma ha generato un'eccezione.
Vorrei verificare se esiste una chiave in un determinato bucket utilizzando Java. Ho esaminato l'API ma non ci sono metodi utili. Ho provato a usare getObject
ma ha generato un'eccezione.
Risposte:
Usa la libreria jets3t. È molto più semplice e robusto di AWS sdk. Usando questa libreria puoi chiamare, s3service.getObjectDetails (). Questo controllerà e recupererà solo i dettagli dell'oggetto (non il contenuto) dell'oggetto. Lancerà un 404 se l'oggetto è mancante. Quindi puoi catturare quell'eccezione e gestirla nella tua app.
Ma affinché funzioni, sarà necessario disporre dell'accesso ListBucket per l'utente su quel bucket. Solo l'accesso a GetObject non funzionerà. Il motivo è che Amazon ti impedirà di verificare la presenza della chiave se non hai accesso a ListBucket. In alcuni casi, anche solo sapere se una chiave è presente o meno sarà sufficiente per gli utenti malintenzionati. Quindi, a meno che non abbiano accesso a ListBucket, non saranno in grado di farlo.
Ora c'è un metodo doesObjectExist nell'API Java ufficiale.
Godere!
doesObjectExist
dall'SDK 2.x (attualmente v2.3.9).
Aggiornare:
Sembra che ci sia una nuova API per controllare proprio questo. Vedi un'altra risposta in questa pagina: https://stackoverflow.com/a/36653034/435605
Post originale:
Uso 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);
}
Nota sull'eccezione: so che le eccezioni non dovrebbero essere utilizzate per il controllo del flusso. Il problema è che Amazon non ha fornito alcuna API per controllare questo flusso, ma solo la documentazione sull'eccezione.
errorMessage
è impostato su "Not Found", ma errorCode
è nullo.
NoSuchKey
. Per un elenco definitivo dei codici di errore S3, consultare la documentazione: docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
Utilizzando l'SDK AWS, utilizza il metodo getObjectMetadata. Il metodo genererà un'eccezione AmazonServiceException se la chiave non esiste.
private AmazonS3 s3;
...
public boolean exists(String path, String name) {
try {
s3.getObjectMetadata(bucket, getS3Path(path) + name);
} catch(AmazonServiceException e) {
return false;
}
return true;
}
In Amazon Java SDK 1.10+, puoi utilizzare getStatusCode()
per ottenere il codice di stato della risposta HTTP, che sarà 404 se l'oggetto non esiste.
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()
consuma meno risorse e la risposta non deve essere chiusa come getObject()
.
Nelle versioni precedenti, è possibile utilizzare getErrorCode()
e verificare la stringa appropriata (dipende dalla versione).
Usa ListObjectsRequest impostando Prefix come chiave.
Codice .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;
}
}
}.
Per PHP (so che la domanda è Java, ma Google mi ha portato qui), puoi utilizzare stream wrapper e file_exists
$bucket = "MyBucket";
$key = "MyKey";
$s3 = Aws\S3\S3Client->factory([...]);
$s3->registerStreamWrapper();
$keyExists = file_exists("s3://$bucket/$key");
Questo codice java controlla se la chiave (file) esiste nel bucket 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;
}
Spezza il tuo percorso in secchio e oggetto. Testare il bucket utilizzando il metodo doesBucketExist
, Testare l'oggetto utilizzando la dimensione dell'elenco (0 nel caso in cui non esista). Quindi questo codice farà:
String bucket = ...;
String objectInBucket = ...;
AmazonS3 s3 = new AmazonS3Client(...);
return s3.doesBucketExist(bucket)
&& !s3.listObjects(bucket, objectInBucket).getObjectSummaries().isEmpty();
Utilizzo di Object isting. Funzione Java per verificare se la chiave specificata esiste in 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;
}
Il modo giusto per farlo in SDK V2, senza il sovraccarico di ottenere effettivamente l'oggetto, è usare S3Client.headObject . Supportato ufficialmente da AWS Change Log .
Codice di esempio:
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;
}
}
C'è un modo semplice per farlo usando il metodo isObjectInBucket () dell'API jetS3t.
Codice d'esempio:
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
}
Le altre risposte sono per AWS SDK v1. Ecco un metodo per AWS SDK v2 (attualmente 2.3.9).
Nota che i metodi getObjectMetadata
e doesObjectExist
non sono attualmente nell'SDK v2! Quindi quelle non sono più opzioni. Siamo costretti a usare o getObject
o listObjects
.
listObjects
le chiamate sono attualmente 12,5 volte più costose da effettuare rispetto a getObject
. Ma AWS addebita anche i dati scaricati, il che aumenta il prezzo getObject
se il file esiste . Finché è molto improbabile che il file esista (ad esempio, hai generato una nuova chiave UUID in modo casuale e devi solo ricontrollare che non sia stata utilizzata), la chiamata getObject
è significativamente più economica secondo il mio calcolo.
Solo per essere sicuro, però, ho aggiunto una range()
specifica per chiedere ad AWS di inviare solo pochi byte del file. Per quanto ne so, l'SDK lo rispetterà sempre e non ti addebiterà il download dell'intero file. Ma non l'ho verificato, quindi affidati a quel comportamento a tuo rischio! (Inoltre, non sono sicuro di come range
si comporti se l'oggetto S3 è lungo 0 byte.)
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;
}
}
Nota: questo codice presuppone s3Client
e log
viene dichiarato e inizializzato altrove. Il metodo restituisce un valore booleano, ma può generare eccezioni.
s3Client.headObject()
V2 per farlo: stackoverflow.com/a/56949742/9814131 , e controllerai il S3Exception
codice di stato 404 per verificare se l'oggetto esiste in base al problema di github github.com/aws/aws-sdk- java-v2 / issues / 297 . Ma immagino che i tuoi siano più progressivi poiché ha un sovraccarico minimo di 0-3 byte.
Ho anche affrontato questo problema quando l'ho usato
String BaseFolder = "3patti_Logs";
S3Object object = s3client.getObject(bucketName, BaseFolder);
Ho ricevuto la chiave di errore non trovata
Quando colpisco e provo
String BaseFolder = "3patti_Logs";
S3Object object = s3client.getObject(bucketName, BaseFolder+"/");
ha funzionato, questo codice funziona con 1.9 jar altrimenti aggiorna a 1.11 e usa doesObjectExist come detto sopra
Come altri hanno già detto, per AWS S3 Java SDK 2.10+ puoi utilizzare l' oggetto HeadObjectRequest per verificare se è presente un file nel tuo bucket S3. Questo agirà come una richiesta GET senza effettivamente ottenere il file.
Codice di esempio poiché altri non hanno effettivamente aggiunto alcun codice sopra:
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
non è necessario.
In alternativa puoi utilizzare la libreria client Minio-Java , la sua Open Source e compatibile con l'API AWS S3.
Puoi usare gli esempi Minio-Java StatObject.java per lo stesso.
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; public class GetObject { public static void main (String [] args) genera NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException { // Nota: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY e my-bucketname lo sono // valori fittizi, sostituiscili con valori originali. // Imposta l'endpoint s3, la regione viene calcolata automaticamente MinioClient s3Client = new MinioClient ("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); InputStream stream = s3Client.getObject ("my-bucketname", "my-objectname"); byte [] buf = nuovo byte [16384]; int bytesRead; while ((bytesRead = stream.read (buf, 0, buf.length))> = 0) { System.out.println (new String (buf, 0, bytesRead)); } stream.close (); } }
Spero possa essere d'aiuto.
Disclaimer: lavoro per Minio