Salin objek dari bucket sumber ke bucket tujuan dalam wilayah yang sama tanpa mengubah konten objek tersebut.
Dengan operasi CopyObject, Anda dapat:
Membuat cadangan objek ke bucket lain dalam wilayah yang sama.
Memindahkan objek antar-bucket tanpa perlu mengunduh dan mengunggah ulang.
Mengubah kelas penyimpanan, daftar kontrol akses (ACL), metadata, atau tag objek dengan menyalin ke kunci yang sama.
Prasyarat
Sebelum menyalin objek, pastikan Anda memiliki:
Izin baca pada objek sumber.
Izin baca dan tulis pada bucket tujuan.
Operasi salin akan gagal jika salah satu izin tersebut tidak tersedia.
Batasan
Salin lintas-wilayah tidak didukung. Misalnya, Anda tidak dapat menyalin objek antara China (Hangzhou) dan China (Shanghai).
Objek yang lebih besar dari 1 GB harus menggunakan metode salin multipart (UploadPartCopy). ossbrowser mendukung objek hingga 5 GB.
Jika kebijakan retensi dikonfigurasi pada bucket sumber atau tujuan, operasi salin akan mengembalikan kesalahan:
The object you specified is immutable.
Pilih metode salin
| Method | Object size | Notes |
|---|---|---|
| ossbrowser | Hingga 5 GB | Tool GUI; tidak memerlukan kode |
| OSS SDKs (CopyObject) | Hingga 1 GB | Direkomendasikan untuk akses programatik |
| OSS SDKs (UploadPartCopy) | Lebih dari 1 GB | Salin multipart; lihat Overview |
| ossutil | Ukuran apa pun | alat CLI |
| CopyObject API | Hingga 1 GB per panggilan | Panggilan API langsung; perhitungan signature diperlukan |
Perilaku penimpaan
Secara default, menyalin objek dengan kunci yang sama seperti objek yang sudah ada di bucket tujuan akan menimpanya. Untuk mencegah penimpaan tidak disengaja, gunakan salah satu metode berikut:
Aktifkan versioning pada bucket tujuan. Objek yang ditimpa akan disimpan sebagai versi sebelumnya dan dapat dipulihkan kapan saja. Untuk detailnya, lihat Versioning.
Atur header `x-oss-forbid-overwrite` ke `true`. Jika kunci tujuan sudah ada, operasi salin akan gagal dan OSS mengembalikan kode kesalahan
FileAlreadyExists.
Pertimbangan biaya
Menyalin sejumlah besar objek dan segera mengatur kelas penyimpanannya ke Deep Cold Archive dapat mengakibatkan biaya permintaan PUT yang tinggi. Untuk mengurangi biaya, konfigurasikan lifecycle rules agar objek secara otomatis dialihkan ke Deep Cold Archive setelah disalin.
Salin objek
Gunakan OSS SDKs
Contoh berikut menggunakan operasi CopyObject untuk menyalin objek berukuran kurang dari 1 GB. Untuk objek lebih dari 1 GB, gunakan UploadPartCopy — lihat Overview.
Semua contoh membaca kredensial dari variabel lingkungan (OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET). Atur variabel ini sebelum menjalankan kode.
Perilaku metadata saat salin
Secara default, OSS menyalin metadata objek sumber ke objek tujuan (mode COPY). Untuk mengganti metadata, atur x-oss-metadata-directive ke REPLACE dan tentukan nilai metadata baru dalam permintaan. Jika Anda mengganti metadata, Anda harus secara eksplisit mendeklarasikan semua bidang metadata — bidang yang dihilangkan akan dihapus dari objek tujuan.
<details> <summary>Python</summary>
import argparse
import alibabacloud_oss_v2 as oss
parser = argparse.ArgumentParser(description="copy object sample")
parser.add_argument('--region', required=True, help='Wilayah tempat bucket berada.')
parser.add_argument('--bucket', required=True, help='Nama bucket tujuan.')
parser.add_argument('--endpoint', help='Titik akhir wilayah.')
parser.add_argument('--key', required=True, help='Kunci objek tujuan.')
parser.add_argument('--source_key', required=True, help='Kunci objek sumber.')
parser.add_argument('--source_bucket', required=True, help='Nama bucket sumber.')
def main():
args = parser.parse_args()
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
cfg = oss.config.load_default()
cfg.credentials_provider = credentials_provider
cfg.region = args.region
if args.endpoint is not None:
cfg.endpoint = args.endpoint
client = oss.Client(cfg)
result = client.copy_object(oss.CopyObjectRequest(
bucket=args.bucket,
key=args.key,
source_key=args.source_key,
source_bucket=args.source_bucket,
))
print(f'status code: {result.status_code},'
f' request id: {result.request_id},'
f' version id: {result.version_id},'
f' hash crc64: {result.hash_crc64},'
f' source version id: {result.source_version_id},'
f' server side encryption: {result.server_side_encryption},'
f' server side data encryption: {result.server_side_data_encryption},'
f' last modified: {result.last_modified},'
f' etag: {result.etag}')
if __name__ == "__main__":
main()</details>
<details> <summary>Java</summary>
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"; // Ganti dengan titik akhir Anda
String region = "cn-hangzhou"; // Ganti dengan wilayah Anda
String sourceBucketName = "srcexamplebucket";
String sourceKey = "srcexampleobject.txt";
String destinationBucketName = "desexamplebucket"; // Harus berada di wilayah yang sama
String destinationKey = "desexampleobject.txt";
EnvironmentVariableCredentialsProvider credentialsProvider =
CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(
sourceBucketName, sourceKey,
destinationBucketName, destinationKey
);
CopyObjectResult result = ossClient.copyObject(copyObjectRequest);
System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
} catch (OSSException oe) {
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
} catch (ClientException ce) {
System.out.println("Client Error: " + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}</details>
<details> <summary>Go</summary>
package main
import (
"context"
"flag"
"log"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)
var (
region string
srcBucketName string
srcObjectName string
destBucketName string
destObjectName string
)
func init() {
flag.StringVar(®ion, "region", "", "Wilayah tempat bucket berada.")
flag.StringVar(&srcBucketName, "src-bucket", "", "Nama bucket sumber.")
flag.StringVar(&srcObjectName, "src-object", "", "Nama objek sumber.")
flag.StringVar(&destBucketName, "dest-bucket", "", "Nama bucket tujuan.")
flag.StringVar(&destObjectName, "dest-object", "", "Nama objek tujuan.")
}
func main() {
flag.Parse()
if len(srcBucketName) == 0 {
log.Fatalf("parameter tidak valid, nama bucket sumber wajib diisi")
}
if len(region) == 0 {
log.Fatalf("parameter tidak valid, wilayah wajib diisi")
}
if len(destBucketName) == 0 {
destBucketName = srcBucketName // Default ke bucket sumber untuk salin dalam bucket yang sama
}
if len(srcObjectName) == 0 {
log.Fatalf("parameter tidak valid, nama objek sumber wajib diisi")
}
if len(destObjectName) == 0 {
log.Fatalf("parameter tidak valid, nama objek tujuan wajib diisi")
}
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
client := oss.NewClient(cfg)
request := &oss.CopyObjectRequest{
Bucket: oss.Ptr(destBucketName),
Key: oss.Ptr(destObjectName),
SourceKey: oss.Ptr(srcObjectName),
SourceBucket: oss.Ptr(srcBucketName),
}
result, err := client.CopyObject(context.TODO(), request)
if err != nil {
log.Fatalf("gagal menyalin objek %v", err)
}
log.Printf("hasil salin objek: %#v\n", result)
}</details>
<details> <summary>PHP</summary>
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
$optsdesc = [
"region" => ['help' => 'Wilayah tempat bucket berada.', 'required' => true],
"endpoint" => ['help' => 'Titik akhir wilayah.', 'required' => false],
"bucket" => ['help' => 'Nama bucket tujuan.', 'required' => true],
"key" => ['help' => 'Kunci objek tujuan.', 'required' => true],
"src-bucket" => ['help' => 'Nama bucket sumber.', 'required' => false],
"src-key" => ['help' => 'Kunci objek sumber.', 'required' => true],
];
$longopts = array_map(fn($key) => "$key:", array_keys($optsdesc));
$options = getopt("", $longopts);
foreach ($optsdesc as $key => $value) {
if ($value['required'] === true && empty($options[$key])) {
echo "Error: --$key wajib diisi. " . $value['help'] . PHP_EOL;
exit(1);
}
}
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($options["region"]);
if (isset($options["endpoint"])) {
$cfg->setEndpoint($options["endpoint"]);
}
$client = new Oss\Client($cfg);
$request = new Oss\Models\CopyObjectRequest(
bucket: $options["bucket"],
key: $options["key"]
);
if (!empty($options["src-bucket"])) {
$request->sourceBucket = $options["src-bucket"];
}
$request->sourceKey = $options["src-key"];
$result = $client->copyObject($request);
printf(
'status code: %s' . PHP_EOL .
'request id: %s' . PHP_EOL,
$result->statusCode,
$result->requestId
);</details>
<details> <summary>Node.js</summary>
const OSS = require('ali-oss');
const client = new OSS({
region: 'yourRegion', // Ganti dengan wilayah Anda
accessKeyId: process.env.OSS_ACCESS_KEY_ID,
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
authorizationV4: true,
bucket: 'examplebucket',
});
async function copyObject() {
try {
const result = await client.copy('destexampleobject.txt', 'srcexampleobject.txt');
console.log(result);
} catch (e) {
console.log(e);
}
}
copyObject();</details>
<details> <summary>C#</summary>
using Aliyun.OSS;
using Aliyun.OSS.Common;
var endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // Ganti dengan titik akhir Anda
var region = "cn-hangzhou"; // Ganti dengan wilayah Anda
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
var sourceBucket = "srcexamplebucket";
var sourceObject = "srcdir/srcobject.txt";
var targetBucket = "destbucket"; // Harus berada di wilayah yang sama
var targetObject = "destdir/destobject.txt";
var conf = new ClientConfiguration();
conf.SignatureVersion = SignatureVersion.V4;
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
client.SetRegion(region);
try
{
var req = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject);
client.CopyObject(req);
Console.WriteLine("Salin objek berhasil");
}
catch (OssException ex)
{
Console.WriteLine("Gagal dengan kode kesalahan: {0}; Info kesalahan: {1}. \nRequestID: {2} \tHostID: {3}",
ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
Console.WriteLine("Gagal dengan info kesalahan: {0}", ex.Message);
}</details>
<details> <summary>Ruby</summary>
require 'aliyun/oss'
client = Aliyun::OSS::Client.new(
endpoint: 'https://oss-cn-hangzhou.aliyuncs.com', # Ganti dengan titik akhir Anda
access_key_id: ENV['OSS_ACCESS_KEY_ID'],
access_key_secret: ENV['OSS_ACCESS_KEY_SECRET']
)
bucket = client.get_bucket('examplebucket')
# Salin objek beserta metadatanya
bucket.copy_object('destobject.txt', 'srcobject.txt',
:meta_directive => Aliyun::OSS::MetaDirective::COPY)
# Salin objek dan ganti metadatanya
bucket.copy_object('destobject.txt', 'srcobject.txt',
:metas => {'year' => '2017'},
:meta_directive => Aliyun::OSS::MetaDirective::REPLACE)</details>
<details> <summary>Android (Java)</summary>
String srcBucketName = "srcbucket";
String srcObjectKey = "dir1/srcobject.txt";
String destBucketName = "destbucket"; // Harus berada di wilayah yang sama
String destObjectKey = "dir2/destobject.txt";
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(
srcBucketName, srcObjectKey,
destBucketName, destObjectKey
);
OSSAsyncTask copyTask = oss.asyncCopyObject(copyObjectRequest,
new OSSCompletedCallback<CopyObjectRequest, CopyObjectResult>() {
@Override
public void onSuccess(CopyObjectRequest request, CopyObjectResult result) {
Log.d("copyObject", "salin berhasil!");
}
@Override
public void onFailure(CopyObjectRequest request,
ClientException clientException,
ServiceException serviceException) {
if (clientException != null) {
clientException.printStackTrace();
}
if (serviceException != null) {
Log.e("ErrorCode", serviceException.getErrorCode());
Log.e("RequestId", serviceException.getRequestId());
Log.e("HostId", serviceException.getHostId());
Log.e("RawMessage", serviceException.getRawMessage());
}
}
});</details>
<details> <summary>iOS (Objective-C)</summary>
OSSCopyObjectRequest *copy = [OSSCopyObjectRequest new];
copy.sourceBucketName = @"sourcebucket";
copy.sourceObjectKey = @"dir1/srcobject.txt";
copy.bucketName = @"destbucket";
copy.objectKey = @"dir2/destobject.txt";
OSSTask *task = [client copyObject:copy];
[task continueWithBlock:^id(OSSTask *task) {
if (!task.error) {
NSLog(@"salin objek berhasil!");
} else {
NSLog(@"salin objek gagal, error: %@", task.error);
}
return nil;
}];</details>
<details> <summary>C++</summary>
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;
int main(void)
{
std::string Endpoint = "yourEndpoint"; // Ganti dengan titik akhir Anda
std::string Region = "yourRegion"; // Ganti dengan wilayah Anda
std::string SourceBucketName = "srcexamplebucket";
std::string CopyBucketName = "destbucket"; // Harus berada di wilayah yang sama
std::string SourceObjectName = "srcdir/srcobject.txt";
std::string CopyObjectName = "destdir/destobject.txt";
InitializeSdk();
ClientConfiguration conf;
conf.signatureVersion = SignatureVersionType::V4;
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
client.SetRegion(Region);
CopyObjectRequest request(CopyBucketName, CopyObjectName);
request.setCopySource(SourceBucketName, SourceObjectName);
auto outcome = client.CopyObject(request);
if (!outcome.isSuccess()) {
std::cout << "CopyObject gagal"
<< ", code: " << outcome.error().Code()
<< ", message: " << outcome.error().Message()
<< ", requestId: " << outcome.error().RequestId() << std::endl;
ShutdownSdk();
return -1;
}
ShutdownSdk();
return 0;
}</details>
<details> <summary>C</summary>
#include "oss_api.h"
#include "aos_http_io.h"
const char *endpoint = "yourEndpoint"; // Ganti dengan titik akhir Anda
const char *region = "yourRegion"; // Ganti dengan wilayah Anda
const char *source_bucket_name = "yourSourceBucketName";
const char *source_object_name = "yourSourceObjectName";
const char *dest_bucket_name = "yourDestBucketName"; // Harus berada di wilayah yang sama
const char *dest_object_name = "yourDestObjectName";
void init_options(oss_request_options_t *options)
{
options->config = oss_config_create(options->pool);
aos_str_set(&options->config->endpoint, endpoint);
aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
aos_str_set(&options->config->region, region);
options->config->signature_version = 4;
options->config->is_cname = 0;
options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
exit(1);
}
aos_pool_t *pool;
aos_pool_create(&pool, NULL);
oss_request_options_t *oss_client_options = oss_request_options_create(pool);
init_options(oss_client_options);
aos_string_t source_bucket, source_object, dest_bucket, dest_object;
aos_table_t *headers = NULL, *resp_headers = NULL;
aos_status_t *resp_status = NULL;
aos_str_set(&source_bucket, source_bucket_name);
aos_str_set(&source_object, source_object_name);
aos_str_set(&dest_bucket, dest_bucket_name);
aos_str_set(&dest_object, dest_object_name);
headers = aos_table_make(pool, 0);
resp_status = oss_copy_object(oss_client_options,
&source_bucket, &source_object,
&dest_bucket, &dest_object,
headers, &resp_headers);
if (aos_status_is_ok(resp_status)) {
printf("salin objek berhasil\n");
} else {
printf("salin objek gagal\n");
}
aos_pool_destroy(pool);
aos_http_io_deinitialize();
return 0;
}</details>
Gunakan ossutil
Gunakan CopyObject API secara langsung
Metode di atas semuanya berbasis pada operasi API CopyObject. Panggil API secara langsung jika kasus penggunaan Anda memerlukan konstruksi permintaan khusus. Panggilan API langsung memerlukan perhitungan signature dalam kode Anda.
Langkah selanjutnya
Untuk menyalin objek lebih dari 1 GB, gunakan operasi UploadPartCopy. Lihat Overview.
Untuk melindungi objek dari penimpaan tidak disengaja, aktifkan Versioning pada bucket tujuan.
Untuk mengelola biaya penyimpanan setelah menyalin, konfigurasikan lifecycle rules agar objek secara otomatis dialihkan ke kelas penyimpanan berbiaya lebih rendah.