You need to enable JavaScript to run this app.
导航

分片上传(Java SDK)

最近更新时间2024.03.21 15:13:15

首次发布时间2021.11.27 17:58:44

如果需要上传较大的对象,建议分成多个数据块(part)来分别上传,最后调用合并分片将上传的数据块合并为一个对象。

注意事项

  • 分片上传前,您必须具有 tos:PutObject 权限,具体操作,请参见权限配置指南
  • 取消分片上传任务前,您必须具有 tos:AbortMultipartUpload 权限,具体操作,请参见权限配置指南
  • 分片编号从 1 开始,最大为 10000。除最后一个分片以外,其他分片大小最小为 4MiB。
  • 上传对象时,对象名必须满足一定规范,详细信息,请参见对象命名规范
  • TOS 是面向海量存储设计的分布式对象存储产品,内部分区存储了对象索引数据,为横向扩展您上传对象和下载对象时的最大吞吐量,和减小热点分区的概率,请您避免使用字典序递增的对象命名方式,详细信息,请参见性能优化
  • 如果桶中已经存在同名对象,则新对象会覆盖已有的对象。如果您的桶开启了版本控制,则会保留原有对象,并生成一个新版本号用于标识新上传的对象。

分片上传步骤

使用 TOS Java SDK 进行分片上传包含以下三个步骤。

  1. 初始化分片上传任务: 调用 createMultipartUpload 接口返回 TOS 创建的全局唯一uploadId
  2. 上传分片:调用 uploadPart 接口上传分片数据。

    说明

    • 对于同一个分片上传任务(通过 uploadId 标识),分片编号(partNumber)标识了该分片在整个对象中的相对位置。若通过同一分片编号多次上传数据,TOS 会覆盖已有的数据,并以最后一次上传的数据为准。
    • uploadPart 接口返回分片数据的 MD5 值,可通过 ETag 字段获取。合并分片时,您需指定当前分片上传任务中已上传的所有分片信息(分片编号、ETag值)。
  3. 完成分片上传:所有分片上传完成后,调用 completeMultipartUpload 接口将所有分片合并成一个完整的对象。

分片上传完整过程

以下代码通过三种上传方式展示如何通过 Java SDK 将本地文件分片上传到目标桶 bucket-example 中的 example_dir 目录下的 example_object.txt 文件。

  1. 将本地文件封装成 FileInputStream 进行分片上传。
import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.comm.io.TosRepeatableBoundedFileInputStream;
import com.volcengine.tos.model.object.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class MultipartUploadWithFileInputStreamFullExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        // 对象名,模拟 example_dir 下的 example_object.txt 文件
        String objectKey = "example_dir/example_object.txt";
        // 本地文件路径,请保证文件存在,暂不支持文件夹功能。
        String filePath = "example_dir/example_file.txt";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        try{
            // 1. 初始化分片上传
            String uploadId = null;
            CreateMultipartUploadInput create = new CreateMultipartUploadInput().setBucket(bucketName).setKey(objectKey);
//            // 如果需要设置对象的元数据,需要在初始化分片上传的时候设置
//            // 以下所有设置参数均为可选,参数值仅供参考,请根据业务实际需要进行设置。
//            ObjectMetaRequestOptions options = new ObjectMetaRequestOptions();
//            // 设置对象访问权限,此处为私有权限
//            options.setAclType(ACLType.ACL_PRIVATE);
//            // 设置对象存储类型
//            options.setStorageClass(StorageClassType.STORAGE_CLASS_STANDARD);
//            // SDK 默认会根据 objectKey 后缀识别 Content-Type,也可以自定义设置
//            options.setContentType("text/plain");
//            // 自定义对象的元数据,对于自定义的元数据,SDK 会自动对 key 添加
//            // "X-Tos-Meta-" 的前缀,因此用户无需自行添加。
//            Map<String, String> custom = new HashMap<>();
//            custom.put("name", "volc_user");
//            // 在 TOS 服务端存储的元数据为:"X-Tos-Meta-name: volc_user"
//            options.setCustomMetadata(custom);
//            create.setOptions(options);

            CreateMultipartUploadOutput createOutput = tos.createMultipartUpload(create);
            System.out.println("createMultipartUpload succeed, uploadId is " + createOutput.getUploadID());

            // 从 createMultipartUpload 结果中获取 uploadId,用于后续的分片上传和合并分片。
            uploadId = createOutput.getUploadID();

            // 2. 上传分片。
            // 假设分片大小统一为 5MB。
            long partSize = 5 * 1024 * 1024;

            // 已上传分片列表,每次上传分片后记录。
            List<UploadedPartV2> uploadedParts = new ArrayList<>();

            // 以下代码展示读取同一个文件到 FileInputStream,按照每 5MB 大小从头到尾读取文件的一部分进行上传。

            // fileSize 为文件总大小
            long fileSize = new File(filePath).length();
            // offset 为读取文件的位置。如果 offset < fileSize,说明已读到文件末尾,不再读取上传(此时文件已上传完成)
            long offset = 0;
            for (int i = 1; offset < fileSize; ++i) {
                try(FileInputStream content = new FileInputStream(filePath);){
                    // 每次只上传文件的一部分,需要跳过前面已上传的部分,即为 offset 长度。
                    content.skip(offset);
                    InputStream wrappedContent = new TosRepeatableBoundedFileInputStream(content, partSize);
                    // 注意 partNumber 从 1 开始计数。
                    int partNumber = i;
                    if (fileSize-offset < partSize) {
                        // 如果 skip 过后剩余的数据长度小于 partSize,即剩余数据长度没有达到 partSize
                        // 说明已到达最后一个分片,需要修改分片大小
                        partSize = fileSize-offset;
                    }
                    UploadPartV2Input input = new UploadPartV2Input().setBucket(bucketName)
                            .setKey(objectKey).setUploadID(uploadId).setPartNumber(partNumber)
                            .setContentLength(partSize).setContent(wrappedContent);
                    UploadPartV2Output output = tos.uploadPart(input);
                    // 存储已上传分片信息,必须设置 partNumber 和 etag
                    uploadedParts.add(new UploadedPartV2().setPartNumber(i).setEtag(output.getEtag()));
                    System.out.printf("uploadPart succeed, partNumber is %d, etag is %s, crc64 value is %s\n",
                            output.getPartNumber(), output.getEtag(), output.getHashCrc64ecma());

                    // 每上传一次分片,需要更新 offset 的值
                    offset += partSize;
                } catch (IOException e) {
                    System.out.println("uploadPart read file failed");
                    e.printStackTrace();
                }
            }

            // 3. 合并已上传的分片
            // 需要设置桶名、对象名、uploadId和已上传的分片列表
            CompleteMultipartUploadV2Input complete = new CompleteMultipartUploadV2Input().setBucket(bucketName)
                    .setKey(objectKey).setUploadID(uploadId);
            complete.setUploadedParts(uploadedParts);
            // 从 2.6.0 版本开始,SDK 支持设置 completeAll 参数
            // 如果设置 completeAll 为 true,则 TOS 会列举当前 uploadId 已上传的所有 part,
            // 并根据 partNumber 的序号排序执行 completeMultipartUpload 操作。
            // 如果设置 completeAll 为 true,则不允许调用 setUploadedParts 设置 uploadedParts,否则报错。
            // complete.setUploadedParts(null);
            // complete.setCompleteAll(true);
            CompleteMultipartUploadV2Output completedOutput = tos.completeMultipartUpload(complete);
            System.out.printf("completeMultipartUpload succeed, etag is %s, crc64 value is %s, location is %s.\n",
                    completedOutput.getEtag(), completedOutput.getHashCrc64ecma(), completedOutput.getLocation());
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("uploadPart failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("uploadPart failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("uploadPart failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}
  1. 将本地文件通过 uploadPartFromFile 接口进行分片上传。如果待上传数据是本地文件,推荐用此接口。
import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.*;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MultipartUploadWithFileFullExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        // 对象名,模拟 example_dir 下的 example_object.txt 文件
        String objectKey = "example_dir/example_object.txt";
        // 本地文件路径,请保证文件存在,暂不支持文件夹功能。
        String filePath = "example_dir/example_file.txt";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        String uploadId = null;
        // 1. 初始化分片上传
        try{
            CreateMultipartUploadInput create = new CreateMultipartUploadInput().setBucket(bucketName).setKey(objectKey);
//            // 如果需要设置对象的元数据,需要在初始化分片上传的时候设置
//            // 以下所有设置参数均为可选,参数值仅供参考,请根据业务实际需要进行设置。
//            ObjectMetaRequestOptions options = new ObjectMetaRequestOptions();
//            // 设置对象访问权限,此处为私有权限
//            options.setAclType(ACLType.ACL_PRIVATE);
//            // 设置对象存储类型
//            options.setStorageClass(StorageClassType.STORAGE_CLASS_STANDARD);
//            // SDK 默认会根据 objectKey 后缀识别 Content-Type,也可以自定义设置
//            options.setContentType("text/plain");
//            // 自定义对象的元数据,对于自定义的元数据,SDK 会自动对 key 添加
//            // "X-Tos-Meta-" 的前缀,因此用户无需自行添加。
//            Map<String, String> custom = new HashMap<>();
//            custom.put("name", "volc_user");
//            // 在 TOS 服务端存储的元数据为:"X-Tos-Meta-name: volc_user"
//            options.setCustomMetadata(custom);
//            create.setOptions(options);

            CreateMultipartUploadOutput createOutput = tos.createMultipartUpload(create);
            System.out.println("createMultipartUpload succeed, uploadId is " + createOutput.getUploadID());

            // 从 createMultipartUpload 结果中获取 uploadId,用于后续的分片上传和合并分片。
            uploadId = createOutput.getUploadID();

            // 2. 上传分片。
            // 假设分片大小统一为 5MB。
            long partSize = 5 * 1024 * 1024;

            // 已上传分片列表,每次上传分片后记录。
            List<UploadedPartV2> uploadedParts = new ArrayList<>();

            // 以下代码展示如何使用 uploadPartFromFile 接口上传分片,按照每 5MB 大小从头到尾读取文件的一部分进行上传。

            // fileSize 为文件总大小
            long fileSize = new File(filePath).length();
            // offset 为读取文件的位置。如果 offset < fileSize,说明已读到文件末尾,不再读取上传(此时文件已上传完成)
            long offset = 0;
            for (int i = 1; offset < fileSize; ++i) {
                // 注意 partNumber 从 1 开始计数。
                int partNumber = i;
                if (fileSize-offset < partSize) {
                    // 如果 skip 过后剩余的数据长度小于 partSize,即剩余数据长度没有达到 partSize
                    // 说明已到达最后一个分片,需要修改分片大小
                    partSize = fileSize-offset;
                }
                UploadPartFromFileInput input = new UploadPartFromFileInput().setBucket(bucketName)
                        .setKey(objectKey).setUploadID(uploadId).setPartNumber(partNumber)
                        .setFilePath(filePath).setPartSize(partSize).setOffset(offset);
                UploadPartFromFileOutput output = tos.uploadPartFromFile(input);
                // 存储已上传分片信息,必须设置 partNumber 和 etag
                uploadedParts.add(new UploadedPartV2().setPartNumber(partNumber).setEtag(output.getEtag()));
                System.out.printf("uploadPart succeed, partNumber is %d, etag is %s, crc64 value is %s\n",
                        output.getPartNumber(), output.getEtag(),
                        output.getHashCrc64ecma());

                // 每上传一次分片,需要更新 offset 的值
                offset += partSize;
            }

            // 3. 合并已上传的分片
            // 需要设置桶名、对象名、uploadId和已上传的分片列表
            CompleteMultipartUploadV2Input complete = new CompleteMultipartUploadV2Input().setBucket(bucketName)
                    .setKey(objectKey).setUploadID(uploadId);
            complete.setUploadedParts(uploadedParts);
            // 从 2.6.0 版本开始,SDK 支持设置 completeAll 参数
            // 如果设置 completeAll 为 true,则 TOS 会列举当前 uploadId 已上传的所有 part,
            // 并根据 partNumber 的序号排序执行 completeMultipartUpload 操作。
            // 如果设置 completeAll 为 true,则不允许调用 setUploadedParts 设置 uploadedParts,否则报错。
            // complete.setUploadedParts(null);
            // complete.setCompleteAll(true);
            CompleteMultipartUploadV2Output completedOutput = tos.completeMultipartUpload(complete);
            System.out.printf("completeMultipartUpload succeed, etag is %s, crc64 value is %s, location is %s.\n",
                    completedOutput.getEtag(), completedOutput.getHashCrc64ecma(), completedOutput.getLocation());
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("multipart upload failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("multipart upload failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("multipart upload failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}
  1. 将 byte 数组作为分片进行上传。
import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.*;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;

public class MultipartUploadWithByteArrayInputStreamFullExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        // 对象名,模拟 example_dir 下的 example_object.txt 文件
        String objectKey = "example_dir/example_object.txt";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        String uploadId = null;
        // 1. 初始化分片上传
        try{
            CreateMultipartUploadInput create = new CreateMultipartUploadInput().setBucket(bucketName).setKey(objectKey);
//            // 如果需要设置对象的元数据,需要在初始化分片上传的时候设置
//            // 以下所有设置参数均为可选,参数值仅供参考,请根据业务实际需要进行设置。
//            ObjectMetaRequestOptions options = new ObjectMetaRequestOptions();
//            // 设置对象访问权限,此处为私有权限
//            options.setAclType(ACLType.ACL_PRIVATE);
//            // 设置对象存储类型
//            options.setStorageClass(StorageClassType.STORAGE_CLASS_STANDARD);
//            // SDK 默认会根据 objectKey 后缀识别 Content-Type,也可以自定义设置
//            options.setContentType("text/plain");
//            // 自定义对象的元数据,对于自定义的元数据,SDK 会自动对 key 添加
//            // "X-Tos-Meta-" 的前缀,因此用户无需自行添加。
//            Map<String, String> custom = new HashMap<>();
//            custom.put("name", "volc_user");
//            // 在 TOS 服务端存储的元数据为:"X-Tos-Meta-name: volc_user"
//            options.setCustomMetadata(custom);
//            options.setServerSideEncryption("AES256");
//            create.setOptions(options);

            CreateMultipartUploadOutput createOutput = tos.createMultipartUpload(create);
            System.out.println("createMultipartUpload succeed, uploadId is " + createOutput.getUploadID());

            // 从 createMultipartUpload 结果中获取 uploadId,用于后续的分片上传和合并分片。
            uploadId = createOutput.getUploadID();

            // 2. 上传分片。

            // 假设分片大小统一为 5MB。
            long partSize = 5 * 1024 * 1024;

            // 已上传分片列表,每次上传分片后记录。
            List<UploadedPartV2> uploadedParts = new ArrayList<>();

            // 以下代码展示如何使用 uploadPart 接口上传内存中的 byte 数组。

            for (int i = 1; i <= 3; ++i) {
                // 注意 partNumber 从 1 开始计数。
                int partNumber = i;
                // byte 数组数据,对于小 size 的数据可以使用。
                // 大 size 的数据用 byte 数组内存开销较大,而且 int 长度最长只能支持到约 4GB,不建议使用。
                byte[] data = new byte[(int)partSize];
                Arrays.fill(data, (byte)'A');
                InputStream content = new ByteArrayInputStream(data);
                UploadPartV2Input input = new UploadPartV2Input().setBucket(bucketName)
                        .setKey(objectKey).setUploadID(uploadId).setPartNumber(partNumber)
                        .setContentLength(partSize).setContent(content);
                UploadPartV2Output output = tos.uploadPart(input);
                // 存储已上传分片信息,必须设置 partNumber 和 etag
                uploadedParts.add(new UploadedPartV2().setPartNumber(partNumber).setEtag(output.getEtag()));
                System.out.printf("uploadPart succeed, partNumber is %d, etag is %s, crc64 value is %s\n",
                        output.getPartNumber(), output.getEtag(), output.getHashCrc64ecma());
            }

            // 3. 合并已上传的分片
            // 需要设置桶名、对象名、uploadId和已上传的分片列表
            CompleteMultipartUploadV2Input complete = new CompleteMultipartUploadV2Input().setBucket(bucketName)
                    .setKey(objectKey).setUploadID(uploadId);
            complete.setUploadedParts(uploadedParts);
            // 从 2.6.0 版本开始,SDK 支持设置 completeAll 参数
            // 如果设置 completeAll 为 true,则 TOS 会列举当前 uploadId 已上传的所有 part,
            // 并根据 partNumber 的序号排序执行 completeMultipartUpload 操作。
            // 如果设置 completeAll 为 true,则不允许调用 setUploadedParts 设置 uploadedParts,否则报错。
            // complete.setUploadedParts(null);
            // complete.setCompleteAll(true);
            CompleteMultipartUploadV2Output completedOutput = tos.completeMultipartUpload(complete);
            System.out.printf("completeMultipartUpload succeed, etag is %s, crc64 value is %s, location is %s.\n",
                    completedOutput.getEtag(), completedOutput.getHashCrc64ecma(), completedOutput.getLocation());
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("multipart upload failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("multipart upload failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("multipart upload failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

取消分片上传任务

您可以通过 abortMultipartUpload 接口来取消分片上传任务。当一个分片任务被取消后, TOS 会将已上传的分片数据删除,同时您无法再对此分片任务进行任何操作。
以下代码展示如何取消桶 bucket-example 中的 example_dir 目录下的 example_object.txt 对象的分片上传任务。

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.AbortMultipartUploadInput;

public class AbortMultipartUploadExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        // 指定的需要取消的分片上传任务的uploadId,
        // 需保证该 uploadId 已通过初始化分片上传接口 createMultipartUpload 调用返回。
        // 否则,对于不存在的 uploadId 会返回 404 not found。
        String uploadId = "the specific uploadId";
        // 与 uploadId 对应的对象 key,模拟 example_dir 下的 example_object.txt 文件
        String objectKey = "example_dir/example_object.txt";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        try{
            AbortMultipartUploadInput input = new AbortMultipartUploadInput().setBucket(bucketName)
                    .setKey(objectKey).setUploadID(uploadId);
            tos.abortMultipartUpload(input);
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("abortMultipartUpload failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("abortMultipartUpload failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("abortMultipartUpload failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

列举已上传的分片信息

您可以通过 SDK 的 listParts 接口列举某个 uploadId 下已经上传的分片列表。
以下代码展示如何列举桶 bucket-example 中的 example_dir 目录下的 example_object.txt 对象所有已上传的分片列表。

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.ListPartsInput;
import com.volcengine.tos.model.object.ListPartsOutput;
import com.volcengine.tos.model.object.UploadedPartV2;

public class ListPartsExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        // 指定的需要列举的分片上传任务的uploadID,
        // 需保证该 uploadId 已通过初始化分片上传接口 createMultipartUpload 调用返回,
        // 否则,对于不存在的 uploadId 会返回 404 not found。
        String uploadId = "the specific uploadId";
        // 与 uploadId 对应的对象 key,模拟 example_dir 下的 example_object.txt 文件
        String objectKey = "example_dir/example_object.txt";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);
        try{
            // maxParts 设置返回的记录最大条数
            int maxParts = 1000;
            // isTruncated 为 true 代表后续还有数据,为 false 代表已经列举完全部数据
            boolean isTruncated = true;
            int partNumberMarker = 0;
            int total = 0;
            while(isTruncated) {
                ListPartsInput input = new ListPartsInput().setBucket(bucketName).setKey(objectKey)
                        // 必须设置 bucket, key, uploadId
                        .setUploadID(uploadId).setPartNumberMarker(partNumberMarker).setMaxParts(maxParts);
                ListPartsOutput output = tos.listParts(input);
                System.out.printf("listParts succeed, is truncated? %b, next partNumber marker is %d \n",
                        output.isTruncated(), output.getNextPartNumberMarker());
                if (output.getUploadedParts() != null) {
                    for (int i = 0; i < output.getUploadedParts().size(); i++) {
                        UploadedPartV2 upload = output.getUploadedParts().get(i);
                        System.out.printf("Uploaded part, partNumber is %d, etag is %s, lastModified is %s, " +
                                "size is %d.\n", upload.getPartNumber(), upload.getEtag(), upload.getLastModified(), upload.getSize());
                    }
                    total += output.getUploadedParts().size();
                }
                isTruncated = output.isTruncated();
                partNumberMarker = output.getNextPartNumberMarker();
            }
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("listParts failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("listParts failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("listParts failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

相关文档