Ich möchte mit Java überprüfen, ob ein Schlüssel in einem bestimmten Bucket vorhanden ist. Ich habe mir die API angesehen, aber es gibt keine nützlichen Methoden. Ich habe versucht zu verwenden, getObject
aber es warf eine Ausnahme.
Ich möchte mit Java überprüfen, ob ein Schlüssel in einem bestimmten Bucket vorhanden ist. Ich habe mir die API angesehen, aber es gibt keine nützlichen Methoden. Ich habe versucht zu verwenden, getObject
aber es warf eine Ausnahme.
Antworten:
Verwenden Sie die jets3t-Bibliothek. Es ist viel einfacher und robuster als das AWS SDK. Mit dieser Bibliothek können Sie s3service.getObjectDetails () aufrufen. Dadurch werden nur die Details des Objekts (nicht der Inhalt) des Objekts überprüft und abgerufen. Es wird eine 404 geworfen, wenn das Objekt fehlt. So können Sie diese Ausnahme abfangen und in Ihrer App behandeln.
Damit dies funktioniert, benötigen Sie jedoch ListBucket-Zugriff für den Benutzer in diesem Bucket. Nur GetObject-Zugriff funktioniert nicht. Der Grund dafür ist, dass Amazon Sie daran hindert, das Vorhandensein des Schlüssels zu überprüfen, wenn Sie keinen ListBucket-Zugriff haben. Nur zu wissen, ob ein Schlüssel vorhanden ist oder nicht, reicht in einigen Fällen auch für böswillige Benutzer aus. Daher können sie dies nicht tun, es sei denn, sie haben ListBucket-Zugriff.
Es gibt jetzt eine doesObjectExist- Methode in der offiziellen Java-API.
Genießen!
doesObjectExist
aus dem 2.x SDK entfernt wurde (derzeit v2.3.9).
Aktualisieren:
Es scheint, dass es eine neue API gibt, um genau das zu überprüfen. Eine weitere Antwort finden Sie auf dieser Seite: https://stackoverflow.com/a/36653034/435605
Ursprünglicher Beitrag:
Verwenden 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);
}
Hinweis zur Ausnahme: Ich weiß, dass Ausnahmen nicht für die Flusskontrolle verwendet werden sollten. Das Problem ist, dass Amazon keine API zur Überprüfung dieses Ablaufs bereitgestellt hat - nur eine Dokumentation über die Ausnahme.
errorMessage
auf "Nicht gefunden" gesetzt ist, aber das errorCode
ist null.
NoSuchKey
. Eine endgültige Liste der S3-Fehlercodes finden Sie in der Dokumentation: docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
Verwenden Sie für das AWS SDK die Methode getObjectMetadata. Die Methode löst eine AmazonServiceException aus, wenn der Schlüssel nicht vorhanden ist.
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+ können Sie getStatusCode()
den Statuscode der HTTP-Antwort abrufen, der 404 lautet, wenn das Objekt nicht vorhanden ist.
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()
verbraucht weniger Ressourcen und die Antwort muss nicht wie geschlossen werden getObject()
.
In früheren Versionen können Sie getErrorCode()
die entsprechende Zeichenfolge verwenden und nach ihr suchen (abhängig von der Version).
Verwenden Sie das ListObjectsRequest-Einstellungspräfix als Schlüssel.
.NET-Code:
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;
}
}
}.
Für PHP (ich weiß, dass die Frage Java ist, aber Google hat mich hierher gebracht) können Sie Stream-Wrapper und file_exists verwenden
$bucket = "MyBucket";
$key = "MyKey";
$s3 = Aws\S3\S3Client->factory([...]);
$s3->registerStreamWrapper();
$keyExists = file_exists("s3://$bucket/$key");
Dieser Java-Code prüft, ob der Schlüssel (die Datei) im s3-Bucket vorhanden ist.
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;
}
Brechen Sie Ihren Weg in Eimer und Objekt. Testen des Buckets mit der Methode doesBucketExist
, Testen des Objekts mit der Größe der Auflistung (0, falls nicht vorhanden). Dieser Code reicht also aus:
String bucket = ...;
String objectInBucket = ...;
AmazonS3 s3 = new AmazonS3Client(...);
return s3.doesBucketExist(bucket)
&& !s3.listObjects(bucket, objectInBucket).getObjectSummaries().isEmpty();
Verwenden von Objectisting. Java-Funktion zum Überprüfen, ob der angegebene Schlüssel in AWS S3 vorhanden ist.
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;
}
Es gibt eine einfache Möglichkeit, dies mit der isObjectInBucket () -Methode der jetS3t-API zu tun.
Beispielcode:
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
}
Die anderen Antworten beziehen sich auf AWS SDK v1. Hier ist eine Methode für AWS SDK v2 (derzeit 2.3.9).
Beachten Sie, dass getObjectMetadata
und doesObjectExist
Methoden derzeit nicht im v2 SDK enthalten sind! Das sind also keine Optionen mehr. Wir sind gezwungen, entweder getObject
oder zu verwenden listObjects
.
listObjects
Anrufe sind derzeit 12,5-mal teurer als getObject
. AWS berechnet jedoch auch Gebühren für heruntergeladene Daten, was den Preis erhöht, getObject
wenn die Datei vorhanden ist . Solange es sehr unwahrscheinlich ist, dass die Datei existiert (Sie haben beispielsweise zufällig einen neuen UUID-Schlüssel generiert und müssen nur überprüfen, ob er nicht verwendet wird), getObject
ist das Aufrufen nach meiner Berechnung erheblich billiger.
Um auf der sicheren Seite zu sein, habe ich eine range()
Spezifikation hinzugefügt , um AWS zu bitten, nur einige Bytes der Datei zu senden. Soweit ich weiß, wird das SDK dies immer respektieren und Ihnen keine Gebühren für das Herunterladen der gesamten Datei berechnen. Aber ich habe das nicht überprüft, also verlasse dich auf dieses Verhalten auf eigenes Risiko! (Ich bin mir auch nicht sicher, wie ich mich range
verhalte, wenn das S3-Objekt 0 Byte lang ist.)
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;
}
}
Hinweis: Dieser Code geht davon aus s3Client
und log
wird an anderer Stelle deklariert und initialisiert. Die Methode gibt einen Booleschen Wert zurück, kann jedoch Ausnahmen auslösen.
s3Client.headObject()
in V2 eine Möglichkeit , dies zu tun: stackoverflow.com/a/56949742/9814131 , und Sie überprüfen den S3Exception
Statuscode 404 des S, um zu überprüfen, ob das Objekt gemäß dem Github-Problem github.com/aws/aws-sdk- vorhanden ist. Java-v2 / Issues / 297 . Aber ich denke, Ihre sind progressiver, da sie nur einen geringen Overhead von 0-3 Bytes haben.
Der richtige Weg, dies in SDK V2 zu tun, ohne das Objekt tatsächlich abzurufen , ist die Verwendung von S3Client.headObject . Offiziell unterstützt von AWS Change Log .
Alternativ können Sie die Minio-Java- Clientbibliothek Open Source verwenden, die mit der AWS S3-API kompatibel ist.
Sie können dafür Minio-Java StatObject.java- Beispiele verwenden.
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; öffentliche Klasse GetObject { public static void main (String [] args) löst NoSuchAlgorithmException, IOException, InvalidKeyException, XmlPullParserException, MinioException {aus // Hinweis: IHR ACCESSKEYID, IHR SECRETACCESSKEY und mein Bucketname sind // Dummy-Werte, bitte durch Originalwerte ersetzen. // s3 Endpunkt setzen, Region wird automatisch berechnet MinioClient s3Client = neuer MinioClient ("https://s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY"); InputStream stream = s3Client.getObject ("mein-Bucket-Name", "mein-Objektname"); Byte [] buf = neues Byte [16384]; int bytesRead; while ((bytesRead = stream.read (buf, 0, buf.length))> = 0) { System.out.println (neuer String (buf, 0, bytesRead)); }} stream.close (); }} }}
Ich hoffe, es hilft.
Haftungsausschluss: Ich arbeite für Minio
Wie bereits erwähnt, können Sie für das AWS S3 Java SDK 2.10+ das HeadObjectRequest- Objekt verwenden, um zu überprüfen, ob sich eine Datei in Ihrem S3-Bucket befindet. Dies verhält sich wie eine GET-Anforderung, ohne die Datei tatsächlich abzurufen.
Beispielcode, da andere oben keinen Code hinzugefügt haben:
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 (NoSuckKeyException e) {
//Log exception for debugging
return false;
}
}
headObjectResponse
. throws Exception
wird auch nicht benötigt.
Ich war auch mit diesem Problem konfrontiert, als ich es benutzte
String BaseFolder = "3patti_Logs";
S3Object object = s3client.getObject(bucketName, BaseFolder);
Ich habe den Fehlerschlüssel nicht gefunden
Wenn ich treffe und es versuche
String BaseFolder = "3patti_Logs";
S3Object object = s3client.getObject(bucketName, BaseFolder+"/");
es hat funktioniert, dieser Code funktioniert mit 1.9 jar, andernfalls aktualisieren Sie auf 1.11 und verwenden Sie doesObjectExist wie oben beschrieben