edit-icon download-icon

MultipartUpload

最終更新日: Sep 20, 2016

OSS では、putObject インターフェイスを使用した OSS へのファイルのアップロードに加えて、マルチパートアップロードモードが提供されます。マルチパートアップロードモードを適用できるシナリオの一部の例を次に示します。

  • ブレークポイントアップロードが必要な場合
  • 100 MB を超えるオブジェクトをアップロードする場合
  • ネットワークの条件が悪く、OSS サーバーとの接続が頻繁に切断される場合
  • ファイルをアップロードする前に、そのサイズを特定できない場合

ここでは、マルチパートアップロードの手順の概要について説明します。

マルチパートアップロードの手順

マルチパートアップロードの初期化

次のように initiateMultipartUpload メソッドを使用して、マルチパートアップロードタスクを初期化します。

  1. String bucketName = "your-bucket-name";
  2. String key = "your-key";
  3. // Initializes an OSSClient
  4. OSSClient client = ...;
  5. // Starts Multipart Upload
  6. InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketName, key);
  7. InitiateMultipartUploadResult initiateMultipartUploadResult = client.initiateMultipartUpload(initiateMultipartUploadRequest);
  8. // Prints UploadId
  9. System.out.println("UploadId: " + initiateMultipartUploadResult.getUploadId());

InitiateMultipartUploadRequest を使用してアップロードするオブジェクトの名前とバケットを指定します。InitiateMultipartUploadRequest では、ObjectMetadata を設定することもできますが、ContentLength を指定する必要はありません。initiateMultipartUpload から返される結果には UploadId が含まれます。これは、マルチパートアップロードタスクの一意の ID です。後の操作でこれを使用します。

次に、パートをアップロードするための 2 つのメソッドを使用します。ローカルディスクからアップロードする場合は Upload Part を使用し、バケットからオブジェクトのコピーを取得するには Upload Part Copy を使用します。

Upload Part ローカルのアップロード

次に、ローカルファイルをマルチパートアップロードします。パス /path/to/file.zip に 1 つのファイルがあるとします。このファイルは大きいので、OSS にマルチパートアップロードする必要があります。

  1. // Sets each part to 5M
  2. final int partSize = 1024 * 1024 * 5;
  3. File partFile = new File("/path/to/file.zip");
  4. // Calculates the number of parts
  5. int partCount = (int) (partFile.length() / partSize);
  6. if (partFile.length() % partSize != 0){
  7. partCount++;
  8. }
  9. // Creates a list to save the ETag and PartNumber of each part after it is uploaded
  10. List<PartETag> partETags = new ArrayList<PartETag>();
  11. for(int i = 0; i < partCount; i++){
  12. // Retrieves the file stream
  13. FileInputStream fis = new FileInputStream(partFile);
  14. // Skips to the start of each part
  15. long skipBytes = partSize * i;
  16. fis.skip(skipBytes);
  17. // Calculates the size of each part
  18. long size = partSize < partFile.length() - skipBytes ?
  19. partSize : partFile.length() - skipBytes;
  20. // Creates an UploadPartRequest and performs multipart upload
  21. UploadPartRequest uploadPartRequest = new UploadPartRequest();
  22. uploadPartRequest.setBucketName(bucketName);
  23. uploadPartRequest.setKey(key);
  24. uploadPartRequest.setUploadId(initiateMultipartUploadResult.getUploadId());
  25. uploadPartRequest.setInputStream(fis);
  26. uploadPartRequest.setPartSize(size);
  27. uploadPartRequest.setPartNumber(i + 1);
  28. UploadPartResult uploadPartResult = client.uploadPart(uploadPartRequest);
  29. // Saves the returned PartETags to the List.
  30. partETags.add(uploadPartResult.getPartETag());
  31. // Closes the file
  32. fis.close();
  33. }

このプログラムの主な目的は、uploadPart メソッドを呼び出して各パートをアップロードすることです。ただし、次の点に注意する必要があります。

  • uploadPart メソッドでは、最後のパートを除くすべてのパートは 100 KB を超えている必要があります。ただし、Upload Part インターフェイスでは、アップロードされたパートのサイズがすぐに検証されるわけではありません (そのパートが最後のパートかどうかがわからないため)。アップロードされたパートのサイズは、マルチパートアップロードが完了して初めて検証されます。
  • OSS は、サーバーから受信したデータパートの MD5 値を ETag ヘッダーに配置し、それをユーザーに返します。
  • ネットワーク経由で転送されたデータにエラーがないことを確認するために、ContentMD5 を設定できます。OSS ではアップロードされたデータの MD5 値が計算され、ユーザーがアップロードした MD5 値と比較されます。それらの値が一致しない場合、InvalidDigest エラーコードが返されます。
  • パート番号の範囲は 1 ~ 10000 です。パート番号がこの範囲を超えている場合、OSS は InvalidArgument エラーコードを返します。
  • 各パートは、アップロードされるとき、次のパートの開始に対応する場所へのストリームを取得します。
  • 各パートがアップロードされた後、OSS から返される結果には PartETag オブジェクトが含まれます。これは、アップロードするパートの ETag と PartNumber の組み合わせです。これは以降の手順で使用するため、保存する必要があります。通常は、これらの PartETag オブジェクトをリストに保存します。

Upload Part ローカルのチャンク形式のアップロード

  • チャンク形式エンコーディングは、マルチパートアップロードでもサポートされます。```javaFile file = new File(filePath);// Sets each part to 5Mfinal int partSize = 5 1024 1024;int fileSize = (int) file.length();// Calculates the number of partsfinal int partCount = (file.length() % partSize != 0) ? (fileSize / partSize + 1) : (fileSize / partSize);List partETags = new ArrayList();

for (int i = 0; i < partCount; i++) { InputStream fin = new BufferedInputStream(new FileInputStream(file)); fin.skip(i partSize); int size = (i + 1 == partCount) ? (fileSize - i partSize) : partSize;

  1. UploadPartRequest req = new UploadPartRequest();
  2. req.setBucketName(bucketName);
  3. req.setKey(key);
  4. req.setPartNumber(i + 1);
  5. req.setPartSize(size);
  6. req.setUploadId(uploadId);
  7. req.setInputStream(fin);
  8. req.setUseChunkEncoding(true); // Uses chunked encoding
  9. UploadPartResult result = client.uploadPart(req);
  10. partETags.add(result.getPartETag());
  11. fin.close();

}

  1. UploadPartRequest インスタンスで、setUseChunkEncoding(true) を設定してチャンク形式エンコーディングを使用してアップロードできます。
  2. ### Upload Part Copy
  3. Upload Part Copy を使用して、既存のオブジェクトからデータをコピーし、オブジェクトをアップロードします。500 MB を超えるオブジェクトをコピーする場合は、Upload Part Copy メソッドを使用することをお勧めします。
  4. ```java
  5. ObjectMetadata objectMetadata = client.getObjectMetadata(sourceBucketName,sourceKey);
  6. long partSize = 1024 * 1024 * 100;
  7. // Obtains the size of the object to be copied
  8. long contentLength = objectMetadata.getContentLength();
  9. // Calculates the number of parts
  10. int partCount = (int) (contentLength / partSize);
  11. if (contentLength % partSize != 0) {
  12. partCount++;
  13. }
  14. System.out.println("total part count:" + partCount);
  15. List<PartETag> partETags = new ArrayList<PartETag>();
  16. long startTime = System.currentTimeMillis();
  17. for (int i = 0; i < partCount; i++) {
  18. System.out.println("now begin to copy part:" + (i+1));
  19. long skipBytes = partSize * i;
  20. // Calculates the size of each part
  21. long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;
  22. // Creates an UploadPartCopyRequest and performs multipart upload
  23. UploadPartCopyRequest uploadPartCopyRequest = new UploadPartCopyRequest();
  24. uploadPartCopyRequest.setSourceKey("/" + sourceBucketName + "/" + sourceKey);
  25. uploadPartCopyRequest.setBucketName(targetBucketName);
  26. uploadPartCopyRequest.setKey(targetKey);
  27. uploadPartCopyRequest.setUploadId(uploadId);
  28. uploadPartCopyRequest.setPartSize(size);
  29. uploadPartCopyRequest.setBeginIndex(skipBytes);
  30. uploadPartCopyRequest.setPartNumber(i + 1);
  31. UploadPartCopyResult uploadPartCopyResult = client.uploadPartCopy(uploadPartCopyRequest);
  32. // Saves the returned PartETags to the List.
  33. partETags.add(uploadPartCopyResult.getPartETag());
  34. System.out.println("now end to copy part:" + (i+1));
  35. }

上記のプログラムでは、uploadPartCopy メソッドが呼び出されて各パートがコピーされます。要件は基本的に UploadPart と同じです。setBeginIndex を使用して、アップロードする次のパートの開始点に対応する位置を見つける必要があります。また、setSourceKey でコピーするオブジェクトも指定する必要があります。

マルチパートアップロードの実行

以下のコードを使用してマルチパートアップロードを実行します。

  1. CompleteMultipartUploadRequest completeMultipartUploadRequest =
  2. new CompleteMultipartUploadRequest(bucketName,key, initiateMultipartUploadResult.getUploadId(), partETags);
  3. // Completes multipart upload
  4. CompleteMultipartUploadResult completeMultipartUploadResult =
  5. client.completeMultipartUpload(completeMultipartUploadRequest);
  6. // Prints the object's ETag
  7. System.out.println(completeMultipartUploadResult.getETag());

上記のコードでは、マルチパートアップロード中に partETags が partETag リストに保存されます。ユーザーから送信されたパートリストを OSS が受信すると、各データパートの有効性が個別に検証されます。すべてのデータパートが検証されると、OSS はこれらのパートを 1 つの完全なオブジェクトに結合します。

マルチパートアップロードタスクのキャンセル

abortMultipartUpload メソッドを使用して、マルチパートアップロードタスクをキャンセルできます。

  1. AbortMultipartUploadRequest abortMultipartUploadRequest =
  2. new AbortMultipartUploadRequest(bucketName, key, uploadId);
  3. // Cancels the multipart upload
  4. client.abortMultipartUpload(abortMultipartUploadRequest);

バケットのすべてのマルチパートアップロードタスクの取得

listMultipartUploads メソッドを使用して、バケット内のすべてのアップロードタスクを取得できます。

  1. // Gets all upload tasks in the bucket
  2. ListMultipartUploadsRequest listMultipartUploadsRequest=new ListMultipartUploadsRequest(bucketName);
  3. MultipartUploadListing listing = client.listMultipartUploads(listMultipartUploadsRequest);
  4. // Traverses all upload tasks
  5. for (MultipartUpload multipartUpload : listing.getMultipartUploads()) {
  6. System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId());
  7. }

注意: 通常の状態で、バケットに 1000 を超えるマルチパートアップロードタスクが含まれる場合、最初の 1000 個が返され、返される結果の IsTruncated パラメーターは false になります。返された NextKeyMarker および NextUploadMarker は、データの読み込みを継続するための次の開始点として使用できます。返されるマルチパートアップロードタスクの数を増やす場合は、MaxUploads パラメーターを変更するか、セグメント化された読み取りに KeyMarker および UploadIdMarker パラメーターを使用することができます。

アップロードされたすべてのパートの情報の取得

listParts メソッドを使用して、アップロードタスクでアップロードされたすべてのパートを取得できます。

  1. ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, uploadId);
  2. // Gets information for all uploaded parts
  3. PartListing partListing = client.listParts(listPartsRequest);
  4. // Traverses all parts
  5. for (PartSummary part : partListing.getParts()) {
  6. System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag());
  7. }

注意: 通常の状態で、バケットに 1000 を超えるマルチパートアップロードタスクが含まれる場合、最初の 1000 個が返され、返される結果の IsTruncated パラメーターは false になります。返された NextPartNumberMarker は、データの読み込みを継続するための次の開始点として使用できます。返されるマルチパートアップロードタスクの数を増やす場合は、MaxParts パラメーターを変更するか、セグメント化された読み取りに PartNumberMarker パラメーターを使用することができます。