详情页标题前

阿里云对象存储OSSJava拷贝文件-云淘科技

详情页1

本文介绍如何将源Bucket中的文件(Object)复制到同一地域下相同或不同目标Bucket中。

注意事项

  • 本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见访问域名和数据中心。
  • 本文以从环境变量读取访问凭证为例。如何配置访问凭证,请参见Java配置访问凭证。

  • 本文以OSS域名新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见新建OSSClient。
  • 拷贝文件时,您必须拥有源文件的读权限及目标Bucket的读写权限。

  • 拷贝文件时,您需要确保源Bucket和目标Bucket均未设置合规保留策略,否则报错The object you specified is immutable.。

  • 不支持跨地域拷贝。例如不能将华东1(杭州)地域存储空间中的文件拷贝到华北1(青岛)地域。

拷贝小文件

对于小于1 GB的文件,您可以通过ossClient.copyObject方法拷贝文件。此方法有两种参数指定方式:

参数指定方式

描述

CopyObjectResult copyObject(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey)

允许指定源存储空间和源文件,以及目标存储空间和目标文件。拷贝后,目标文件的内容及元信息与源文件相同,称为简单拷贝。

CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest)

允许指定目标文件的元信息和拷贝的限制条件。如果拷贝操作的源文件地址和目标文件地址相同,则直接替换源文件的元信息。

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 matchingETagConstraints)

nonmatchingEtagConstraints

拷贝的限制条件。如果源文件的ETag值和用户提供的ETag值不相等,则执行拷贝操作,否则返回错误。

setNonmatchingETagConstraints(List nonmatchingEtagConstraints)

unmodifiedSinceConstraint

拷贝的限制条件。如果传入参数中的时间等于或者晚于文件实际修改时间,则执行拷贝操作,否则返回错误。

setUnmodifiedSinceConstraint(Date unmodifiedSinceConstraint)

modifiedSinceConstraint

拷贝的限制条件。如果源文件在指定的时间之后被修改过,则执行拷贝操作,否则返回错误。

setModifiedSinceConstraint(Date modifiedSinceConstraint)

CopyObjectResult的参数说明请参见下表。

参数

描述

方法

etag

OSS文件唯一性标识。

String getETag()

lastModified

文件最后修改时间。

Date getLastModified()

拷贝小文件有以下几种拷贝形式。

  • 简单拷贝

    以下代码用于通过简单拷贝将srcexamplebucket中的srcexampleobject.txt文件拷贝到目标存储空间desexamplebucket中的desexampleobject.txt文件。

    import com.aliyun.oss.ClientException;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.OSSException;
    import com.aliyun.oss.model.*;
    
    public class Demo {
        public static void main(String[] args) throws Exception {
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // 填写源Bucket名称。
            String sourceBucketName = "srcexamplebucket";
            // 填写源Object的完整路径,完整路径中不能包含Bucket名称。
            String sourceKey = "srcexampleobject.txt";
            // 填写与源Bucket处于同一地域的目标Bucket名称。
            String destinationBucketName = "desexamplebucket";
            // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
            String destinationKey = "desexampleobject.txt";
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
    
            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.ClientException;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.OSSException;
    import com.aliyun.oss.model.*;
    
    public class Demo {
        public static void main(String[] args) throws Exception {
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // 填写源Bucket名称。
            String sourceBucketName = "srcexamplebucket";
            // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
            String sourceKey = "srcexampleobject.txt";
            // 填写与源Bucket处于同一地域的目标Bucket名称。
            String destinationBucketName = "desexamplebucket";
            // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
            String destinationKey = "desexampleobject.txt";
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
    
            try {
                // 创建CopyObjectRequest对象。
                CopyObjectRequest copyObjectRequest = new CopyObjectRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
    
                // 设置新的文件元信息。
                ObjectMetadata meta = new ObjectMetadata();
                meta.setContentType("text/plain");
                // 指定CopyObject操作时是否覆盖同名目标Object。此处设置为true,表示禁止覆盖同名Object。
                // meta.setHeader("x-oss-forbid-overwrite", "true");
                // 指定拷贝的源地址。
                // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/recode-test.txt");
                // 如果源Object的ETag值和您提供的ETag相等,则执行拷贝操作,并返回200 OK。
                // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
                // 如果源Object的ETag值和您提供的ETag不相等,则执行拷贝操作,并返回200 OK。
                // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
                // 如果指定的时间等于或者晚于文件实际修改时间,则正常拷贝文件,并返回200 OK。
                // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
                // 如果源Object在指定时间后被修改过,则执行拷贝操作。
                // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
                // 指定设置目标Object元信息的方式。此处设置为COPY,表示复制源Object的元数据到目标Object。
                // meta.setHeader(OSSHeaders.COPY_OBJECT_METADATA_DIRECTIVE, "COPY");
                // 指定OSS创建目标Object时使用的服务器端加密算法。
                // meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
                // 表示KMS托管的用户主密钥,该参数仅在x-oss-server-side-encryption为KMS时有效。
                // meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, "9468da86-3509-4f8d-a61e-6eab1eac****");
                // 指定OSS创建目标Object时的访问权限,此处设置为Private,表示只有Object的拥有者和授权用户有该Object的读写权限,其他用户没有权限操作该Object。
                // meta.setHeader(OSSHeaders.OSS_OBJECT_ACL, CannedAccessControlList.Private);
                // 指定Object的存储类型。此处设置为Standard,表示标准存储类型。
                // meta.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard);
                // 指定Object的对象标签,可同时设置多个标签。
                // meta.setHeader(OSSHeaders.OSS_TAGGING, "a:1");
                // 指定设置目标Object对象标签的方式。此处设置为COPY,表示复制源Object的对象标签到目标Object。
                // 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)。分片拷贝分为三步:

  1. 通过ossClient.initiateMultipartUpload初始化分片拷贝任务。

  2. 通过ossClient.uploadPartCopy进行分片拷贝。除最后一个分片外,其它分片都要大于100KB。

  3. 通过ossClient.completeMultipartUpload提交分片拷贝任务。

以下代码用于通过分片拷贝将srcexamplebucket中的srcexampleobject.txt文件拷贝到目标存储空间desexamplebucket中的desexampleobject.txt文件。

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写源Bucket名称。
        String sourceBucketName = "srcexamplebucket";
        // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
        String sourceKey = "srcexampleobject.txt";
        // 填写与源Bucket处于同一地域的目标Bucket名称。
        String destinationBucketName = "desexamplebucket";
        // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
        String destinationKey = "desexampleobject.txt";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        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 partETags = new ArrayList();
            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");
                // 指定源Object的拷贝范围。例如设置bytes=0~1023,表示拷贝1~1024字节的内容。
                // headers.put(OSSHeaders.COPY_SOURCE_RANGE, "bytes=0~1023");
                // 如果源Object的ETag值和您提供的ETag相等,则执行拷贝操作,并返回200 OK。
                // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
                // 如果源Object的ETag值和您提供的ETag不相等,则执行拷贝操作,并返回200 OK。
                // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
                // 如果指定的时间等于或者晚于文件实际修改时间,则正常拷贝文件,并返回200 OK。
                // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
                // 如果源Object在用户指定的时间以后被修改过,则执行拷贝操作。
                // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
                // uploadPartCopyRequest.setHeaders(headers);
                UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest);

                // 将返回的分片ETag保存到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。

内容没看懂? 不太想学习?想快速解决? 有偿解决: 联系专家

阿里云企业补贴进行中: 马上申请

腾讯云限时活动1折起,即将结束: 马上收藏

同尘科技为腾讯云授权服务中心。

购买腾讯云产品享受折上折,更有现金返利:同意关联,立享优惠

转转请注明出处:https://www.yunxiaoer.com/158037.html

(0)
上一篇 2023年12月10日
下一篇 2023年12月10日
详情页2

相关推荐

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
本站为广大会员提供阿里云、腾讯云、华为云、百度云等一线大厂的购买,续费优惠,保证底价,买贵退差。