全部产品
Search
文档中心

Object Storage Service:Salin objek

更新时间:Mar 21, 2026

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

MethodObject sizeNotes
ossbrowserHingga 5 GBTool GUI; tidak memerlukan kode
OSS SDKs (CopyObject)Hingga 1 GBDirekomendasikan untuk akses programatik
OSS SDKs (UploadPartCopy)Lebih dari 1 GBSalin multipart; lihat Overview
ossutilUkuran apa punalat CLI
CopyObject APIHingga 1 GB per panggilanPanggilan 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(&region, "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

Salin srcObject dari srcBucket ke examplebucket:

ossutil api copy-object --bucket examplebucket --key exampleobject --copy-source /srcBucket/srcObject

Untuk petunjuk instalasi, lihat Install ossutil. Untuk referensi parameter lengkap, lihat copy-object.

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.