マルチパートアップロード
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 パラメーターを使用することができます。