すべてのプロダクト
Search
ドキュメントセンター

:MultipartUpload

最終更新日:Dec 22, 2023

マルチパートアップロード

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

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

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

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

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

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

String bucketName = "your-bucket-name";
String key = "your-key";

// Initializes an OSSClient
OSSClient client = ...;
// Starts Multipart Upload
InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketName, key);
InitiateMultipartUploadResult initiateMultipartUploadResult = client.initiateMultipartUpload(initiateMultipartUploadRequest);
// Prints UploadId
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 にマルチパートアップロードする必要があります。

// Sets each part to 5M
final int partSize = 1024 * 1024 * 5;
File partFile = new File("/path/to/file.zip");
// Calculates the number of parts
int partCount = (int) (partFile.length() / partSize);
if (partFile.length() % partSize != 0){
    partCount++;
}
// Creates a list to save the ETag and PartNumber of each part after it is uploaded
List<PartETag> partETags = new ArrayList<PartETag>();
for(int i = 0; i < partCount; i++){
    // Retrieves the file stream
    FileInputStream fis = new FileInputStream(partFile);
    // Skips to the start of each part
    long skipBytes = partSize * i;
    fis.skip(skipBytes);
    // Calculates the size of each part
    long size = partSize < partFile.length() - skipBytes ?
            partSize : partFile.length() - skipBytes;
    // Creates an UploadPartRequest and performs multipart upload
    UploadPartRequest uploadPartRequest = new UploadPartRequest();
    uploadPartRequest.setBucketName(bucketName);
    uploadPartRequest.setKey(key);
    uploadPartRequest.setUploadId(initiateMultipartUploadResult.getUploadId());
    uploadPartRequest.setInputStream(fis);
    uploadPartRequest.setPartSize(size);
    uploadPartRequest.setPartNumber(i + 1);
    UploadPartResult uploadPartResult = client.uploadPart(uploadPartRequest);
    // Saves the returned PartETags to the List.
    partETags.add(uploadPartResult.getPartETag());
    // Closes the file
    fis.close();
}

このプログラムの主な目的は、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;

UploadPartRequest req = new UploadPartRequest();
req.setBucketName(bucketName);
req.setKey(key);
req.setPartNumber(i + 1);
req.setPartSize(size);
req.setUploadId(uploadId);
req.setInputStream(fin);
req.setUseChunkEncoding(true);  // Uses chunked encoding

UploadPartResult result = client.uploadPart(req);
partETags.add(result.getPartETag());

fin.close();

}

UploadPartRequest インスタンスで、setUseChunkEncoding(true) を設定してチャンク形式エンコーディングを使用してアップロードできます。
### Upload Part Copy

Upload Part Copy を使用して、既存のオブジェクトからデータをコピーし、オブジェクトをアップロードします。500 MB を超えるオブジェクトをコピーする場合は、Upload Part Copy メソッドを使用することをお勧めします。
```java
ObjectMetadata objectMetadata = client.getObjectMetadata(sourceBucketName,sourceKey);

long partSize = 1024 * 1024 * 100;
// Obtains the size of the object to be copied
long contentLength = objectMetadata.getContentLength();

// Calculates the number of parts
int partCount = (int) (contentLength / partSize);
if (contentLength % partSize != 0) {
    partCount++;
}
System.out.println("total part count:" + partCount);
List<PartETag> partETags = new ArrayList<PartETag>();

long startTime = System.currentTimeMillis();
for (int i = 0; i < partCount; i++) {
     System.out.println("now begin to copy part:" + (i+1));
     long skipBytes = partSize * i;
// Calculates the size of each part
     long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;
// Creates an UploadPartCopyRequest and performs multipart upload
     UploadPartCopyRequest uploadPartCopyRequest = new UploadPartCopyRequest();
     uploadPartCopyRequest.setSourceKey("/" + sourceBucketName + "/" + sourceKey);
     uploadPartCopyRequest.setBucketName(targetBucketName);
     uploadPartCopyRequest.setKey(targetKey);
     uploadPartCopyRequest.setUploadId(uploadId);
     uploadPartCopyRequest.setPartSize(size);
     uploadPartCopyRequest.setBeginIndex(skipBytes);
     uploadPartCopyRequest.setPartNumber(i + 1);
     UploadPartCopyResult uploadPartCopyResult = client.uploadPartCopy(uploadPartCopyRequest);
// Saves the returned PartETags to the List.
      partETags.add(uploadPartCopyResult.getPartETag());
      System.out.println("now end to copy part:" + (i+1));
}

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

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

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

CompleteMultipartUploadRequest completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(bucketName,key, initiateMultipartUploadResult.getUploadId(), partETags);

// Completes multipart upload
CompleteMultipartUploadResult completeMultipartUploadResult =
        client.completeMultipartUpload(completeMultipartUploadRequest);

// Prints the object's ETag
System.out.println(completeMultipartUploadResult.getETag());

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

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

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

AbortMultipartUploadRequest abortMultipartUploadRequest =
            new AbortMultipartUploadRequest(bucketName, key, uploadId);

// Cancels the multipart upload
client.abortMultipartUpload(abortMultipartUploadRequest);

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

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

// Gets all upload tasks in the bucket
ListMultipartUploadsRequest listMultipartUploadsRequest=new ListMultipartUploadsRequest(bucketName);
MultipartUploadListing listing = client.listMultipartUploads(listMultipartUploadsRequest);

// Traverses all upload tasks
for (MultipartUpload multipartUpload : listing.getMultipartUploads()) {
    System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId());
}

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

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

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

ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, uploadId);

// Gets information for all uploaded parts
PartListing partListing = client.listParts(listPartsRequest);

// Traverses all parts
for (PartSummary part : partListing.getParts()) {
    System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag());
}

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