Ich möchte große Dateien aus Google Cloud Storage mit der von Google bereitgestellten Java-Bibliothek com.google.cloud.storage herunterladen. Ich habe Arbeitscode, aber ich habe noch eine Frage und ein Hauptproblem:So laden Sie eine große Datei aus Google Cloud Storage mithilfe von Java mit Prüfsummensteuerung
Mein Hauptanliegen ist, wann ist der Dateiinhalt tatsächlich heruntergeladen? Während (Verweise auf den folgenden Code) storage.get(blobId)
, während blob.reader()
oder während reader.read(bytes)
? Dies wird sehr wichtig, wenn es darum geht, wie mit einer ungültigen Prüfsumme zu behandeln, was muss ich tun, um tatsächlich auszulösen, dass die Datei wieder über das Netzwerk abgerufen wird?
Die einfachere Frage ist: Gibt es eingebaute Funktionalität, um MD5 (oder CRC32C) auf die erhaltene Datei in der Google Bibliothek zu tun? Vielleicht muss ich es nicht selbst implementieren.
Hier versucht, meine Methode große Dateien von Google Cloud Storage herunterladen:
private static final int MAX_NUMBER_OF_TRIES = 3;
public Path downloadFile(String storageFileName, String bucketName) throws IOException {
// In my real code, this is a field populated in the constructor.
Storage storage = Objects.requireNonNull(StorageOptions.getDefaultInstance().getService());
BlobId blobId = BlobId.of(bucketName, storageFileName);
Path outputFile = Paths.get(storageFileName.replaceAll("/", "-"));
int retryCounter = 1;
Blob blob;
boolean checksumOk;
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
do {
LOGGER.debug("Start download file {} from bucket {} to Content Store (try {})", storageFileName, bucketName, retryCounter);
blob = storage.get(blobId);
if (null == blob) {
throw new CloudStorageCommunicationException("Failed to download file after " + retryCounter + " tries.");
}
if (Files.exists(outputFile)) {
Files.delete(outputFile);
}
try (ReadChannel reader = blob.reader();
FileChannel channel = new FileOutputStream(outputFile.toFile(), true).getChannel()) {
ByteBuffer bytes = ByteBuffer.allocate(128 * 1024);
int bytesRead = reader.read(bytes);
while (bytesRead > 0) {
bytes.flip();
messageDigest.update(bytes.array(), 0, bytesRead);
channel.write(bytes);
bytes.clear();
bytesRead = reader.read(bytes);
}
}
String checksum = Base64.encodeBase64String(messageDigest.digest());
checksumOk = checksum.equals(blob.getMd5());
if (!checksumOk) {
Files.delete(outputFile);
messageDigest.reset();
}
} while (++retryCounter <= MAX_NUMBER_OF_TRIES && !checksumOk);
if (!checksumOk) {
throw new CloudStorageCommunicationException("Failed to download file after " + MAX_NUMBER_OF_TRIES + " tries.");
}
return outputFile;
}
Macht Sinn! Wenn ich eine ungültige Prüfsumme feststelle, gibt es eine Möglichkeit, die Datei com.google.cloud.storage dazu zu zwingen, die Datei erneut herunterzuladen und nicht aus einem Cache zu holen? –
würde ich nicht stören. Wenn Sie eine ungültige Prüfsumme erhalten, war der Fehler sehr wahrscheinlich ein Netzwerkproblem und wird beim zweiten Mal nicht auftreten. Außerdem werden HTTPS-Lesevorgänge, die mit Anmeldeinformationen vorgenommen werden, mit ziemlicher Sicherheit nicht zwischengespeichert, es sei denn, Sie befinden sich hinter einer besonders seltsamen Unternehmensfirewall. Nichtsdestotrotz könnten Sie die meisten Caches mit Sicherheit überspringen, indem Sie einfach einen zusätzlichen Nonsense-URL-Parameter hinzufügen, wie zum Beispiel "& skipCaching = 12345". –
Das Problem ist nicht der HTTP-Cache, sondern der Cache in der von google bereitgestellten Java-Bibliothek (Link in der obigen Frage). JavaDoc for ReadChannel gibt an, dass "Implementierungen dieser Klasse Daten möglicherweise intern puffern, um Remoteaufrufe zu reduzieren". Hier ist eine Seite, die über die Überprüfung der Prüfsumme spricht, aber meine Frage nicht beantwortet, soweit ich das sehe: https://cloud.google.com/storage/docs/hashes-etags Ich arbeite also leider nicht direkt mit URLs. –