2016-12-13 20 views
2

googleが提供するJavaライブラリcom.google.cloud.storageを使用してGoogle Cloud Storageから大きなファイルをダウンロードします。私は作業コードを持っていますが、まだ1つの質問と1つの大きな懸念があります:チェックサムコントロール付きJavaを使用してGoogle Cloud Storageから大きなファイルをダウンロードする方法

私の主な関心事は、ファイルの内容が実際にダウンロードされるのはいつですか?中に(の)、blob.reader()の間またはreader.read(bytes)の間に(下のコードへの参照)?これは非常に重要です。無効なチェックサムを処理するには、ファイルがネットワーク経由で再度フェッチされるように実際にトリガーする必要がありますか?

もっと簡単な質問は次のとおりです。受信したファイルをGoogleライブラリでmd5(またはcrc32c)チェックする機能は組み込まれていますか?たぶん私は自分でそれを実装する必要はありません。ここで

は、Googleのクラウドストレージから大きなファイルをダウンロードしようとしている私の方法です:

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

答えて

2

google-cloud-javaストレージライブラリは、通常のHTTPS/TCPの正しさチェックを超えてデータを読み取るときに、チェックサムを独自に検証しません。受け取ったデータのMD5を既知のMD5と比較した場合、ファイル全体をダウンロードしてからread()の結果を返す必要があります。非常に大きなファイルの場合は実行不可能です。

MD5の比較をさらに強化する必要がある場合は、何をしているかは良い考えです。これが1回限りの作業である場合は、gsutilコマンドラインツールを使用することができます。これは、これと同じ種類の追加チェックを行います。

+0

意味があります!無効なチェックサムを検出した場合は、com.google.cloud.storageライブラリにファイルを再度ダウンロードし、キャッシュからフェッチしないように強制する方法がありますか? –

+0

私は気にしません。無効なチェックサムを取得した場合、そのエラーはネットワーク上の問題である可能性が高く、2回目には発生しません。また、特に奇妙な企業のファイアウォールの背後にいなければ、資格情報で行われたHTTPS読み取りはほとんど確実にキャッシュされません。それにもかかわらず、 "&skipCaching = 12345"のような特別なナンセンスURLパラメータを追加するだけで、ほとんどのキャッシュをスキップできます。 –

+0

問題はHTTPキャッシュではなく、Googleが提供するJavaライブラリのキャッシュ(上記の質問のリンク)です。 ReadChannelのJavaDocは、「このクラスの実装は、データを内部的にバッファリングしてリモート呼び出しを減らすことができる」と述べています。ここでは、チェックサム検証について説明していますが、私の知る限り質問に答えることはできません。https://cloud.google.com/storage/docs/hashes-etagsしたがって、私はURLを直接残念ながら使用していません。 –

0

ReadChannelのjavadocが言うように:このクラスの

実装は、リモート呼び出しを減らすために、内部のデータをバッファリングすることができます。

ですから、blob.reader()から取得する実装では、ファイル全体をキャッシュいくつかのバイトまたは何も、ちょうどあなたがread()を呼び出したとき、バイトのためのバイトをフェッチすることができます。あなたは知らないだろうし、気にしないでください。

IOExceptionをスローし、使用した他の方法では表示されないため、read()を呼び出すだけで実際にダウンロードされると言います。あなたはlibのthe sourcesでもこれを見ることができます。

Btw。図書館のJavaDocsにある例にもかかわらず、ではなく、>= 0を確認する必要があります。 0は、何も読み込まれていないことを意味し、ストリームの終わりに達していません。ストリームの終わりは-1を返すことによって通知されます。

チェックサムチェックに失敗した後に再試行するには、ブロブから新しいリーダーを取得します。何かがダウンロードされたデータをキャッシュしている場合は、読者自身。したがって、BLOBから新しいリーダーを取得した場合、ファイルはリモートから再ダウンロードされます。

+0

はい、私はJavaDocを読んでいます。あなたが言及したように、それはあまり役に立たない。これは答えではないので、あなたが私のように無知であるという声明だけを投票します。また、バイトチェックも問題ありません。チェックはBlob :: readerのJavaDocに従っているので、チャンネルがブロックモードであると仮定します。 –

+0

私はあなたほど無知ではありません。私が言ったように、readメソッドはネットワークの読み込みを行います。スローされた 'IOException'からこれを見ることができます。完全に有効な答えを下げても、人々はそれ以上の答えをあなたに与えることを奨励しません。誤った例を見つけても、自分のコードでエラーを繰り返す必要はありません。リターンコードが「0」の場合、ストリームの終わりに達したということだけではなく、悪意のある例が変更できないということです。 – Vampire

+0

私はJavaDocをReadableByteChannelに読み込んでいますが、チャンネルがブロックモードで、少なくとも1バイトがバッファに残っていれば、少なくとも1バイトが読み込まれるまでこのメソッドはブロックされることが保証されています。 –

関連する問題