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

追加上传(Android SDK)

最近更新时间2024.02.04 18:31:00

首次发布时间2022.12.01 16:31:39

SDK 支持通过 appendObject 接口追加写对象。追加写是指在已上传的对象末尾追加内容,只能对类型为 Appendable 的对象使用此接口。通过直接上传或分片上传创建的对象类型为 Normal,而通过 appendObject 接口上传的对象为 Appendable 类型。

注意事项

使用 appendObject 接口时, 对象的大小限制说明如下:

  • 每次追加的大小不能小于 128KiB,追加对象总大小不能大于 5GiB。
  • 通过 appendObject 创建的对象,对其进行 putObject 操作,对象被覆盖且对象类型由 Appendable 变为 Normal。反之通过 putObject 上传的对象不支持追加写操作。
  • appendObject 创建的对象不支持拷贝。
  • 如果您的存储桶处于开启或者暂停多版本功能的状态下,或存储桶的类型为低频存储,则无法使用appendObject 接口追加对象。

示例代码

以下代码展示如何追加写对象到目标桶中。

import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosException;
import com.volcengine.tos.comm.common.ACLType;
import com.volcengine.tos.comm.common.StorageClassType;
import com.volcengine.tos.model.object.AppendObjectInput;
import com.volcengine.tos.model.object.AppendObjectOutput;
import com.volcengine.tos.model.object.ObjectMetaRequestOptions;

import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class AppendObjectExample extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = "your access key";
        String secretKey = "your secret key";
        String securityToken = "your security token";

        String bucketName = "your bucket name";
        String objectKey = "your object key";

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_display_message);
        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey, securityToken);

        Thread tosThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    // 第一次追加写,请确保传输的数据长度大于等于 128KB
                    byte[] data1 = new byte[128 * 1024];
                    Arrays.fill(data1, (byte) 'A');
                    ByteArrayInputStream stream = new ByteArrayInputStream(data1);
                    // 如果需要设置 appendable 对象的元数据,可在第一次追加写的时候设置,后续无需再添加
                    ObjectMetaRequestOptions options = new ObjectMetaRequestOptions();
                    // 设置对象访问权限,此处为私有权限
                    options.setAclType(ACLType.ACL_PRIVATE);
                    // 设置对象存储类型
                    options.setStorageClass(StorageClassType.STORAGE_CLASS_STANDARD);
                    // SDK 默认会根据 objectKey 后缀识别 Content-Type,也可以自定义设置
                    options.setContentType("application/json");
                    // 自定义对象的元数据,对于自定义的元数据,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);

                    // 注意:当前 TOS 使用 appendObject 接口时需要传入数据长度和偏移量
                    long contentLength = data1.length;
                    long offset = 0;
                    AppendObjectInput input = new AppendObjectInput().setBucket(bucketName).setKey(objectKey)
                            .setContent(stream).setContentLength(contentLength).setOffset(offset).setOptions(options);
                    AppendObjectOutput output = tos.appendObject(input);
                    Log.i("appendObject", "appendObject first time succeed, object's nextAppendOffset is " + output.getNextAppendOffset());
                    Log.i("appendObject", "appendObject first time succeed, object's crc64 is " + output.getHashCrc64ecma());

                    // 第二次追加写
                    byte[] data2 = new byte[128 * 1024 + 1024];
                    Arrays.fill(data2, (byte) 'B');
                    // 偏移量为当前对象的长度,即从对象末尾追加写数据。
                    contentLength = data2.length;
                    offset = data1.length;
                    // 由于 SDK 默认开启 crc64 校验,从第二次追加写开始,之后每次调用都需要传入上一次追加写请求返回的 crc64 值。
                    String preHashCrc64 = output.getHashCrc64ecma();
                    input = new AppendObjectInput().setBucket(bucketName).setKey(objectKey).setContent(new ByteArrayInputStream(data2))
                            .setOffset(offset).setContentLength(contentLength).setPreHashCrc64ecma(preHashCrc64);
                    output = tos.appendObject(input);
                    Log.i("appendObject", "appendObject second time succeed, object's nextAppendOffset is " + output.getNextAppendOffset());
                    Log.i("appendObject", "appendObject second time succeed, object's crc64 is " + output.getHashCrc64ecma());

                    // 第三次追加写
                    byte[] data3 = new byte[256 * 1024 + 1024];
                    Arrays.fill(data3, (byte) 'C');
                    // 偏移量为当前对象的长度,即从对象末尾追加写数据。
                    contentLength = data3.length;
                    offset = data1.length + data2.length;
                    // 由于 SDK 默认开启 crc64 校验,从第二次追加写开始,之后每次调用都需要传入上一次追加写请求返回的 crc64 值。
                    preHashCrc64 = output.getHashCrc64ecma();
                    input = new AppendObjectInput().setBucket(bucketName).setKey(objectKey).setContent(new ByteArrayInputStream(data3))
                            .setOffset(offset).setContentLength(contentLength).setPreHashCrc64ecma(preHashCrc64);
                    output = tos.appendObject(input);
                    Log.i("appendObject", "appendObject third time succeed, object's nextAppendOffset is " + output.getNextAppendOffset());
                    Log.i("appendObject", "appendObject third time succeed, object's crc64 is " + output.getHashCrc64ecma());
                } catch (TosException e) {
                    Log.e("TosException", "appendObject failed");
                    e.printStackTrace();
                }
            }
        });

        tosThread.start();
    }
}

相关文档

关于追加上传的 API 文档,请参见 AppendObject