このトピックでは、同じリージョン内のバケット内またはバケット間でオブジェクトをコピーする方法について説明します。
使用上の注意
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントが使用されています。同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスするには、内部エンドポイントを使用します。サポートされているリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。
このトピックでは、アクセス認証情報は環境変数から取得されます。アクセス認証情報を構成する方法の詳細については、「アクセス認証情報の構成」をご参照ください。
このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスが作成されます。カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、「一般的なシナリオの構成例」をご参照ください。
オブジェクトをコピーするには、ソースオブジェクトに対する読み取り権限と、デスティネーションバケットに対する読み取りおよび書き込み権限が必要です。
ソースバケットとデスティネーションバケットに保存ポリシーが構成されていないことを確認してください。構成されている場合、指定したオブジェクトは変更不可です。 というエラーメッセージが返されます。
ソースバケットとデスティネーションバケットは同じリージョンにある必要があります。たとえば、中国 (杭州) リージョンにあるバケットから中国 (青島) リージョンにある別のバケットにオブジェクトをコピーすることはできません。
小規模オブジェクトのコピー
ossClient.copyObject メソッドを使用して、サイズが 1 GB 未満のオブジェクトをコピーできます。次の表に、ossClient.copyObject の構成方法を示します。
構成方法 | 説明 |
CopyObjectResult copyObject(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) | ソースバケット、ソースオブジェクト、デスティネーションバケット、およびデスティネーションオブジェクトを指定できます。オブジェクトがコピーされると、デスティネーションオブジェクトのコンテンツとメタデータは、ソースオブジェクトのコンテンツとメタデータと同じになります。このメソッドはシンプルコピーと呼ばれます。 |
CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest) | デスティネーションオブジェクトのメタデータとコピー条件を指定できます。ソースオブジェクトとデスティネーションオブジェクトの URL が同じ場合、リクエストで指定されたメタデータがソースオブジェクトのメタデータを置き換えます。 |
次の表に、CopyObjectRequest に対して構成できるパラメーターを示します。
パラメーター | 説明 | メソッド |
sourceBucketName | ソースバケットの名前。 | setSourceBucketName(String sourceBucketName) |
sourceKey | ソースオブジェクトの名前。 | setSourceKey(String sourceKey) |
destinationBucketName | デスティネーションバケットの名前。 | setDestinationBucketName(String destinationBucketName) |
destinationKey | デスティネーションオブジェクトの名前。 | setDestinationKey(String destinationKey) |
newObjectMetadata | デスティネーションオブジェクトのメタデータ。 | setNewObjectMetadata(ObjectMetadata newObjectMetadata) |
matchingETagConstraints | コピー操作の条件。ソースオブジェクトの ETag 値がリクエストで指定された ETag 値と同じ場合、コピー操作が実行されます。そうでない場合は、エラーが返されます。 | setMatchingETagConstraints(List<String> matchingETagConstraints) |
nonmatchingEtagConstraints | コピー操作の条件。ソースオブジェクトの ETag 値がリクエストで指定された ETag 値と異なる場合、コピー操作が実行されます。そうでない場合は、エラーが返されます。 | setNonmatchingETagConstraints(List<String> nonmatchingEtagConstraints) |
unmodifiedSinceConstraint | コピー操作の条件。リクエストで指定された時刻がソースオブジェクトの実際の更新時刻以降の場合、コピー操作が実行されます。そうでない場合は、エラーが返されます。 | setUnmodifiedSinceConstraint(Date unmodifiedSinceConstraint) |
modifiedSinceConstraint | コピー操作の条件。リクエストで指定された時刻より後にソースオブジェクトが更新された場合、コピー操作が実行されます。そうでない場合は、エラーが返されます。 | setModifiedSinceConstraint(Date modifiedSinceConstraint) |
次の表に、CopyObjectResult に対して構成できるパラメーターを示します。
パラメーター | 説明 | メソッド |
etag | オブジェクトの一意のタグ。 | String getETag() |
lastModified | オブジェクトの最終更新時刻。 | Date getLastModified() |
次のいずれかの方法を使用して、小規模オブジェクトをコピーできます。
シンプルコピー
次のコードは、シンプルコピーを使用して、srcexamplebucket バケットにある srcexampleobject.txt という名前のオブジェクトを、desexamplebucket バケットにある desexampleobject.txt という名前のオブジェクトにコピーする方法の例を示しています。
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.model.*; public class Demo { public static void main(String[] args) throws Exception { // この例では、中国 (杭州) リージョンのエンドポイントが使用されています。実際のエンドポイントを指定してください。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が構成されていることを確認してください。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // ソースバケットの名前を指定します。 String sourceBucketName = "srcexamplebucket"; // ソースオブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。 String sourceKey = "srcexampleobject.txt"; // デスティネーションバケットの名前を指定します。デスティネーションバケットは、ソースバケットと同じリージョンにある必要があります。 String destinationBucketName = "desexamplebucket"; // デスティネーションオブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。 String destinationKey = "desexampleobject.txt"; // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。 String region = "cn-hangzhou"; // OSSClient インスタンスを作成します。 // OSSClient が不要になったら、shutdown メソッドを呼び出してリソースを解放します。 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); try { // オブジェクトをコピーします。 CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey); System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified()); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } finally { if (ossClient != null) { ossClient.shutdown(); } } } }CopyObjectRequest を使用してオブジェクトをコピーする
次のコードは、CopyObjectRequest を使用して、srcexamplebucket バケットにある srcexampleobject.txt という名前のオブジェクトを、desexamplebucket バケットにある desexampleobject.txt という名前のオブジェクトにコピーする方法の例を示しています。
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.model.*; public class Demo { public static void main(String[] args) throws Exception { // この例では、中国 (杭州) リージョンのエンドポイントが使用されています。実際のエンドポイントを指定してください。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が構成されていることを確認してください。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // ソースバケットの名前を指定します。 String sourceBucketName = "srcexamplebucket"; // ソースオブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。 String sourceKey = "srcexampleobject.txt"; // デスティネーションバケットの名前を指定します。デスティネーションバケットは、ソースバケットと同じリージョンにある必要があります。 String destinationBucketName = "desexamplebucket"; // デスティネーションオブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。 String destinationKey = "desexampleobject.txt"; // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。 String region = "cn-hangzhou"; // OSSClient インスタンスを作成します。 // OSSClient が不要になったら、shutdown メソッドを呼び出してリソースを解放します。 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); try { // CopyObjectRequest オブジェクトを作成します。 CopyObjectRequest copyObjectRequest = new CopyObjectRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey); // オブジェクトの新しいメタデータを構成します。 ObjectMetadata meta = new ObjectMetadata(); meta.setContentType("text/plain"); // CopyObject 操作で同じ名前のオブジェクトを上書きするかどうかを指定します。この例では、このパラメーターは true に設定されており、操作では同じ名前のオブジェクトが上書きされないことを指定しています。 // meta.setHeader("x-oss-forbid-overwrite", "true"); // ソースオブジェクトのパスを指定します。 // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/recode-test.txt"); // ソースオブジェクトの ETag 値がリクエストで指定された ETag 値と同じ場合、OSS はオブジェクトをコピーし、200 OK を返します。 // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****"); // ソースオブジェクトの ETag 値がリクエストで指定された ETag 値と異なる場合、OSS はオブジェクトをコピーし、200 OK を返します。 // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****"); // リクエストで指定された時刻がオブジェクトの更新時刻以降の場合、OSS はオブジェクトをコピーし、200 OK を返します。 // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z"); // リクエストで指定された時刻より後にソースオブジェクトが更新された場合、OSS はオブジェクトをコピーします。 // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z"); // デスティネーションオブジェクトのメタデータを構成するために使用されるメソッドを指定します。この例では、メソッドは COPY に設定されており、ソースオブジェクトのメタデータがデスティネーションオブジェクトにコピーされることを指定しています。 // meta.setHeader(OSSHeaders.COPY_OBJECT_METADATA_DIRECTIVE, "COPY"); // オブジェクトの作成時にデスティネーションオブジェクトの暗号化に使用されるサーバー側暗号化アルゴリズムを指定します。 // meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION); // Key Management Service (KMS) によって管理されるカスタマーマスターキー (CMK) を指定します。このパラメーターは、x-oss-server-side-encryption を KMS に設定した場合にのみ有効になります。 // meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, "9468da86-3509-4f8d-a61e-6eab1eac****"); // デスティネーションオブジェクトのアクセス制御リスト (ACL) を指定します。この例では、ACL は private に設定されており、オブジェクトの所有者と承認されたユーザーのみがオブジェクトに対する読み取りおよび書き込み権限を持つことを指定しています。 // meta.setHeader(OSSHeaders.OSS_OBJECT_ACL, CannedAccessControlList.Private); // デスティネーションオブジェクトのストレージクラスを指定します。この例では、ストレージクラスは Standard に設定されています。 // meta.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard); // デスティネーションオブジェクトのタグを指定します。オブジェクトに複数のタグを一度に指定できます。 // meta.setHeader(OSSHeaders.OSS_TAGGING, "a:1"); // デスティネーションオブジェクトのタグを構成するために使用されるメソッドを指定します。この例では、メソッドは COPY に設定されており、ソースオブジェクトのタグがデスティネーションオブジェクトにコピーされることを指定しています。 // meta.setHeader(OSSHeaders.COPY_OBJECT_TAGGING_DIRECTIVE, "COPY"); copyObjectRequest.setNewObjectMetadata(meta); // ソースオブジェクトをコピーします。 CopyObjectResult result = ossClient.copyObject(copyObjectRequest); System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified()); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } finally { if (ossClient != null) { ossClient.shutdown(); } } } }
大規模オブジェクトのコピー
サイズが 1 GB を超えるオブジェクトをコピーするには、オブジェクトをパーツに分割し、UploadPartCopy を使用してパーツを順番にコピーする必要があります。マルチパートコピーを実装するには、次の手順を実行します。
ossClient.initiateMultipartUpload を使用して、マルチパートコピータスクを開始します。
ossClient.uploadPartCopy を使用してパーツをコピーします。最後のパーツを除くすべてのパーツは 100 KB より大きくする必要があります。
ossClient.completeMultipartUpload を使用して、マルチパートコピータスクを完了します。
次のコードは、マルチパートコピーを使用して、srcexamplebucket バケットにある srcexampleobject.txt という名前のオブジェクトを、desexamplebucket バケットにある desexampleobject.txt という名前のオブジェクトにコピーする方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) throws Exception {
// この例では、中国 (杭州) リージョンのエンドポイントが使用されています。実際のエンドポイントを指定してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が構成されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// ソースバケットの名前を指定します。
String sourceBucketName = "srcexamplebucket";
// ソースオブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。
String sourceKey = "srcexampleobject.txt";
// デスティネーションバケットの名前を指定します。デスティネーションバケットは、ソースバケットと同じリージョンにある必要があります。
String destinationBucketName = "desexamplebucket";
// デスティネーションオブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。
String destinationKey = "desexampleobject.txt";
// バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
String region = "cn-hangzhou";
// OSSClient インスタンスを作成します。
// OSSClient が不要になったら、shutdown メソッドを呼び出してリソースを解放します。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
ObjectMetadata objectMetadata = ossClient.getObjectMetadata(sourceBucketName, sourceKey);
// コピーするオブジェクトのサイズをクエリします。
long contentLength = objectMetadata.getContentLength();
// 各パーツのサイズを 10 MB に設定します。単位:バイト。
long partSize = 1024 * 1024 * 10;
// パーツの総数を計算します。
int partCount = (int) (contentLength / partSize);
if (contentLength % partSize != 0) {
partCount++;
}
System.out.println("total part count:" + partCount);
// マルチパートコピータスクを開始します。InitiateMultipartUploadRequest 操作を呼び出して、デスティネーションオブジェクトのメタデータを指定できます。
InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(destinationBucketName, destinationKey);
// ソースオブジェクトの ContentType と UserMetadata の値をコピーします。デフォルトでは、マルチパートコピーを使用する場合、ソースオブジェクトの ContentType と UserMetadata の値はコピーされません。
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(objectMetadata.getContentType());
metadata.setUserMetadata(objectMetadata.getUserMetadata());
initiateMultipartUploadRequest.setObjectMetadata(metadata);
InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
String uploadId = initiateMultipartUploadResult.getUploadId();
// マルチパートコピータスクを開始します。
List<PartETag> partETags = new ArrayList<PartETag>();
for (int i = 0; i < partCount; i++) {
// 各パーツのサイズを計算します。
long skipBytes = partSize * i;
long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;
// UploadPartCopyRequest オブジェクトを作成します。UploadPartCopyRequest 操作を呼び出して、条件を指定できます。
UploadPartCopyRequest uploadPartCopyRequest =
new UploadPartCopyRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
uploadPartCopyRequest.setUploadId(uploadId);
uploadPartCopyRequest.setPartSize(size);
uploadPartCopyRequest.setBeginIndex(skipBytes);
uploadPartCopyRequest.setPartNumber(i + 1);
//Map headers = new HashMap();
// ソースオブジェクトのパスを指定します。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/desexampleobject.txt");
// コピーするデータの範囲を指定します。たとえば、bytes を 0〜1023 に設定すると、ソースオブジェクトの最初の 1,024 バイトがコピーされます。
// headers.put(OSSHeaders.COPY_SOURCE_RANGE, "bytes=0~1023");
// ソースオブジェクトの ETag 値がリクエストで指定された ETag 値と同じ場合、OSS はオブジェクトをコピーし、200 OK を返します。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
// ソースオブジェクトの ETag 値がリクエストで指定された ETag 値と異なる場合、OSS はオブジェクトをコピーし、200 OK を返します。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
// リクエストで指定された時刻がオブジェクトの更新時刻以降の場合、OSS はオブジェクトをコピーし、200 OK を返します。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
// リクエストで指定された時刻より後にソースオブジェクトが更新された場合、OSS はオブジェクトをコピーします。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
// uploadPartCopyRequest.setHeaders(headers);
UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest);
// 返された PartETag を partETags に保存します。
partETags.add(uploadPartCopyResult.getPartETag());
}
// マルチパートコピータスクを完了します。
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
destinationBucketName, destinationKey, uploadId, partETags);
ossClient.completeMultipartUpload(completeMultipartUploadRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}リファレンス
小規模オブジェクトのコピー
小規模オブジェクトのコピーを呼び出すことができる API 操作の詳細については、「CopyObject」をご参照ください。
大規模オブジェクトのコピー
大規模オブジェクトのコピーに使用される完全なサンプルコードの詳細については、GitHub にアクセスしてください。
大規模オブジェクトのコピーを呼び出すことができる API 操作の詳細については、「UploadPartCopy」をご参照ください。