Object管理
所有文档
menu

对象存储 BOS

Object管理

产品详情自助选购

上传Object

最简单的上传

  • 基本流程

    1. 创建BOSClient 类的实例。
    2. 调用BOSClient.putObject()方法,可以通过如下四种方式上传Object:文件、数据流、二进制串和字符串的形式。
    3. 对返回的PutObjectResponse类型实例,执行getETag()获得上传成功的ETag。
  • 示例代码

    // 获取指定文件
    File file = new File(<FilePath>);     //指定文件路径
    
    // 以文件形式上传Object
    PutObjectResponse putObjectFromFileResponse = 
        client.putObject(<BucketName>, <ObjectKey>, file);
    
    // 获取数据流
    InputStream inputStream = new FileInputStream(<FilePath>);
    
    // 以数据流形式上传Object
    PutObjectResponse putObjectResponseFromInputStream = 
        client.putObject(<BucketName>, <ObjectKey>, inputStream);
    
    // 以二进制串上传Object
    PutObjectResponse putObjectResponseFromByte = 
        client.putObject(<BucketName>, <ObjectKey>, <byte>);
    
    // 以字符串上传Object
    PutObjectResponse putObjectResponseFromString = 
        client.putObject(<BucketName>, <ObjectKey>, <string>);
    
    // 打印ETag
    System.out.println(putObjectFromFileResponse.getETag());

    说明:Object以文件的形式上传到BOS中,putObject函数支持不超过5GB的Object上传。在putObject请求处理成功后,BOS会在Header中返回Object的ETag作为文件标识。

  • 完整示例

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.development.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.PutObjectResponse;public class ExampleActivity extends Activity {
    
      private String bucketName = <BucketName>;
      private String objectKey = <ObjectKey>;
      byte[] b = null;
      String str = <PutString>;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 获取指定文件
                    File file = new File("/path/to/file.zip");
    
                    // 以文件形式上传Object
                    PutObjectResponse putObjectFromFileResponse = client.putObject(<BucketName>, <ObjectKey>, file);
    
                    // 获取数据流
                    InputStream inputStream = new FileInputStream("/path/to/test.zip");
    
                    // 以数据流形式上传Object
                    PutObjectResponse putObjectResponseFromInputStream = client.putObject(<BucketName>, <ObjectKey>, inputStream);
    
                    // 以二进制串上传Object
                    PutObjectResponse putObjectResponseFromByte = client.putObject(<BucketName>, <ObjectKey>, b);
    
                    // 以字符串上传Object
                    PutObjectResponse putObjectResponseFromString = client.putObject(<BucketName>, <ObjectKey>, str);
    
                    // 打印ETag
                    System.out.println(putObjectFromFileResponse.getETag());
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 
            }
        }).start();
    }}

设定Object的Copy属性

CopyObject接口用于将一个已经存在的Object拷贝到另外一个Object,拷贝过程中会对源Object的Etag或修改状态进行判断,根据判断结果决定是否执行拷贝。详细的参数解释如下:

名称 类型 描述 是否必需
x-bce-copy-source-if-match String 如果源Object的ETag值和用户提供的ETag相等,则执行拷贝操作,否则拷贝失败。
x-bce-copy-source-if-none-match String 如果源Object的ETag和用户提供的ETag不相等,则执行拷贝操作,否则拷贝失败。
x-bce-copy-source-if-unmodified-since String 如果源object在x-bce-copy-source-if-unmodified-since之后没被修改,则执行拷贝操作,否则拷贝失败。
x-bce-copy-source-if-modified-since String 如果源object在x-bce-copy-source-if-modified-since之后被修改了,则执行拷贝操作,否则拷贝失败。
  • 示例代码

    // 初始化BosClient
    BosClient client = ...;
    
    // 创建CopyObjectRequest对象
    CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
    
    // 设置新的Metadata
    Map<String, String> userMetadata = new HashMap<String, String>();
    userMetadata.put("<user-meta-key>","<user-meta-value>");
    ObjectMetadata meta = new ObjectMetadata();
    meta.setUserMetadata(userMetadata);
    copyObjectRequest.setNewObjectMetadata(meta);
    
    //copy-source-if-match
    copyObjectRequest.withETag("111111111183bf192b57a4afc76fa632");
    //copy-source-if-none-match
    copyObjectRequest.withNoMatchingETagConstraint("111111111183bf192b57a4afc76fa632");
    
    Date modifiedSinceConstraint = new Date();    
    SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);  
    df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));        
    String date = df.format(modifiedSinceConstraint);
    
    //copy-source-if-modified-since
    copyObjectRequest.withModifiedSinceConstraint(date);
    
    //copy-source-if-unmodified-since
    copyObjectRequest.withUnmodifiedSinceConstraint(date);
    
    // 复制Object
    CopyObjectResponse copyObjectResponse = client.copyObject(copyObjectRequest);

设定Object的Http Header

BOS支持您在上传object时设定Http Header。

  • 基本流程

    1. 创建ObjectMetadata类的实例。
    2. 执行setContentLength()/setContentType()等方法对Http Header进行设定。
    3. 将设定后的meta作为参数加入client.putObject()中。
  • 示例代码

    // 创建ObjectMetadata类的实例
    ObjectMetadata meta = new ObjectMetadata();
    
    // 设置ContentLength大小
    meta.setContentLength(<Length>);
    
    // 设置ContentType
    meta.setContentType("application/json");
    
    client.putObject(<BucketName>, <ObjectKey>, content, meta);

    说明:header可设置的属性有:"Cache-Control"、"Content-Encoding"、"Content-Disposition"、"Expires"

  • 完整示例

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.ObjectMetadata;
    import com.baidubce.services.bos.model.PutObjectResponse;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 获取数据流
                    InputStream inputStream = new FileInputStream("/path/to/test.zip");
    
                    // 创建ObjectMetadata类的实例
                    ObjectMetadata meta = new ObjectMetadata();
    
                    // 设置ContentLength大小
                    meta.setContentLength(1000);
    
                    // 设置ContentType
                    meta.setContentType("application/json");
    
                    PutObjectResponse putObjectResponseFromInputStream = client.putObject(bucketName, objectKey, inputStream, meta);
    
                     // 打印ETag
                    System.out.println(putObjectResponseFromInputStream.getETag());
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 
            }
        }).start();
    }}

用户自定义元数据

BOS支持用户自定义元数据来对Object进行描述。

  • 基本流程

    1. 创建ObjectMetadata类的实例。
    2. 执行addUserMetadata()方法对Http Header进行自定义元数据。
    3. 将设定后的meta作为参数加入client.putObject()中。
  • 示例代码

    // 设置自定义元数据name的值为my-data
    meta.addUserMetadata("name", "my-data");	  
    
    // 上传Object
    client.putObject(<BucketName>, <ObjectKey>, <Content>, meta);

    说明:在上面代码中,用户自定义了一个名字为”name”,值为”my-data”的元数据。当用户下载此Object的时候,此元数据也可以一并得到。一个Object可以有多个类似的参数,但所有的User Meta总大小不能超过2KB。

  • 完整示例

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.ObjectMetadata;
    import com.baidubce.services.bos.model.PutObjectResponse;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 获取数据流
                    InputStream inputStream = new FileInputStream("/path/to/test.zip");
    
                    // 创建ObjectMetadata类的实例
                    ObjectMetadata meta = new ObjectMetadata();
    
                    // 自定义元数据
                    meta.addUserMetadata("name", "my-data");	    
    
                    PutObjectResponse putObjectResponseFromInputStream = client.putObject(<BucketName>, <ObjectKey>, inputStream, meta);
    
                     // 打印ETag
                    System.out.println(putObjectResponseFromInputStream.getETag());
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 
            }
        }).start();
    }}

Append方式上传Object

BOS支持AppendObject,即以追加写的方式上传文件,适用场景如日志追加及直播等实时视频文件上传。通过AppendObject操作创建的Object类型为Appendable Object,可以对该Object追加数据;而通过PutObject上传的Object是Normal Object,不可进行数据追加写。AppendObject大小限制为0~5G。

  • 示例代码

    public void AppendObject(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1) {
          // 获取指定文件
          File file = new File("/path/to/file.zip");
          // 获取数据流
          InputStream inputStream = new FileInputStream("/path/to/test.zip");
    
          // 以文件形式上传Object
          AppendObjectResponse appendObjectFromFileResponse = client.appendObject(bucketName, objectKey, file);
          // 以数据流形式上传Object
          AppendObjectResponse appendObjectResponseFromInputStream = client.appendObject(bucketName, objectKey, inputStream);
          // 以二进制串上传Object
          AppendObjectResponse appendObjectResponseFromByte = client.appendObject(bucketName, objectKey, byte1);
          // 以字符串上传Object
          AppendObjectResponse appendObjectResponseFromString = client.appendObject(bucketName, objectKey, string1);
    
          // 向AppendFile追加内容
          Long nextOffset = appendObjectFromFileResponse.getNextAppendOffset();
          AppendObjectRequest request =new AppendObjectRequest(bucketName, objectKey,
          RestartableInputStream.wrap(string1.getBytes()));
          request.withOffset(nextOffset);
          AppendObjectResponse appendResponse = client.appendObject(request);      
    }

获取上传进度

Android SDK支持在上传过程中实时提供上传进度信息。目前支持PutObject, AppendObject, UploadPart以及PutSuperObjectFromFile四个接口。进度上传接口的使用必须构造对应的Request (PutObjectRequest, AppendObjectRequest, UploadPartRequest以及PutSuperObjectRequest)。

SDK提供的上传进度回调接口如下,您可以在其中定义上传过程中您所需要的操作,如更新界面等等。

public interface BceProgressCallback<T extends AbstractBceRequest> {
      // request为上传的请求
      // currentSize为当前上传的大小(单位:byte)
      // totalSize为本次请求需要上传的总大小(单位:byte)
      void onProgress(T request, long currentSize, long totalSize);
  • PutObject示例代码:

    PutObjectRequest request = new PutObjectRequest(this.bucketName, "test", file);
    ObjectMetadata objectMetadata = new ObjectMetadata();
    objectMetadata.setContentType("text/plain");
    request.setObjectMetadata(objectMetadata);
    request.setProgressCallback(new BosProgressCallback<PutObjectRequest>() {
        @Override
        public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
            Log.e(currentSize + "", totalSize + "");
        }
    });
    String eTag = this.client.putObject(request).getETag();
  • AppendObject示例代码:

    ObjectMetadata objectMetadata = new ObjectMetadata();
    objectMetadata.setContentType("text/plain");
    AppendObjectRequest request = new AppendObjectRequest(this.bucketName, "test", file);
    request.setObjectMetadata(objectMetadata);
    AppendObjectResponse response = this.client.appendObject(request);
    Long nextOffset = response.getNextAppendOffset();
    request.withOffset(nextOffset);
    request.setProgressCallback(new BosProgressCallback<AppendObjectRequest>() {
        @Override
        public void onProgress(AppendObjectRequest request, long currentSize, long totalSize) {
            Log.e(currentSize + "", totalSize + "");
        }
    });
    response = this.client.appendObject(request);
  • UploadPart示例代码:

    UploadPartRequest request = new UploadPartRequest().withBucketName(this.bucketName)
            .withKey("test").withUploadId(uploadId).withPartNumber(1).withPartSize(8000)
            .withInputStream(fis);
    request.setProgressCallback(new BosProgressCallback<UploadPartRequest>() {
        @Override
        public void onProgress(UploadPartRequest request, long currentSize, long totalSize) {
            Log.e(currentSize + "", totalSize + "");
        }
    });
    UploadPartResponse response = this.client.uploadPart(request);
  • PutSuperObjectFromFile示例代码:

    PutSuperObjectRequest request = new PutSuperObjectRequest().withBucketName(this.bucketName)
            .withKey("test").withPartSize(1024*1024*2L).withFile(file);
    request.setProgressCallback(new BosProgressCallback<PutSuperObjectRequest>() {
        @Override
        public void onProgress(PutSuperObjectRequest request, long currentSize, long totalSize) {
            Log.e(currentSize + "", totalSize + "");
        }
    });
    PutSuperObjectResponse response = this.client.putSuperObjectFromFile(request);

    目前,SDK默认上传进度的回调粒度为2048个字节。您可以通过如下方法设置一个更适合您App应用的回调粒度:

    BosClientConfiguration config=new BosClientConfiguration(); config.setUploadSegmentPart(1024);

注意: 该值必须在1-8192之间,如不在该范围内,Android SDK会强制设置为2048.

取消接口

Android SDK支持在请求过程中取消本次请求,其中上传请求中剩余的数据将不再会上传至BOS,下载请求中取消操作会关闭连接,执行中的操作会抛出Request is canceled!异常

所有的BOS操作都可以使用取消接口,但是已经完成的请求无法被取消,已经完成的操作也不会抛出异常

// 以上传接口取消为例
final PutObjectRequest req = new PutObjectRequest(<BucketName>, <ObjectName>,
         new FileInputStream(<FilePath>));
Runnable cancelTask = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace()
        }
        // 取消本次上传请求
        req.cancel();
    }
};
new Thread(cancelTask).start();
client.putObject(req);

同步回调

Android SDK支持BOS服务端同步回调接口,通过在PutObjectRequest中,设置process参数,就可以在上传完成后,让BOS服务端主动调用回调接口来达到通知客户目的。

PutObjectRequest request = new PutObjectRequest({bucket}, {object}, {inputStream});
// 设置x-bce-process参数
request.setProcess({x-bce-process});
PutObjectResponse response = client.putObject(request);
// 获取返回的http status code
int statusCode = response.getHttpResponse().getStatusCode();
// 获取返回的回调接口返回的数据
string callbackString = response.getServerCallbackReturnBody();

查看Bucket中的Object

简单查询

查看Bucket中Object列表。

  • 基本流程

    1. 创建BOSClient类的实例。
    2. 执行BOSClient.listObjects(bucketName)方法,会返回ListObjectsResponse类的实例。
    3. 对ListObjectsResponse类型可以进行getBuckets()/getOwner()/getMetadata()操作。
  • 示例代码

    // 获取指定Bucket下的所有Object信息
    ListObjectsResponse listing = client.listObjects(<BucketName>);
    
    // 遍历所有Object
    for (BosObjectSummary objectSummary : listing.getContents()) {
        System.out.println("ObjectKey: " + objectSummary.getKey());
    }

    说明: listObjects( )方法返回ListObjectsResponse对象,ListObjectsResponse对象包含了此次listObject请求的返回结果。用户可以通过ListObjectsResponse中的getContents方法获取所有Object的描述信息。

    • 默认情况下,如果Bucket中的Object数量大于1000,则只会返回1000个Object,并且返回结果中IsTruncated值为True,并返回NextMarker做为下次读取的起点。
    • 若想获取更多的Object,可以使用Marker参数分次读取,请参考扩展查询
  • 完整示例

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.BosObjectSummary;
    import com.baidubce.services.bos.model.ListObjectsResponse;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyId>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 获取指定Bucket下的所有Object信息
                    ListObjectsResponse listing = client.listObjects(<BucketName>);
    
                    // 遍历所有Object
                    for (BosObjectSummary objectSummary : listing.getContents()) {
                        System.out.println("ObjectKey: " + objectSummary.getKey());
                    }               	                    
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                }
            }
        }).start();
    }}

扩展查询

用户可以通过设置ListObjectsRequest参数来完成更多扩展查询操作设置。ListObjectsRequest中可以设置的扩展参数如下:

参数名称 说明 默认值
MaxKeys 设定此次返回Object的最大个数,不可超过1000。 1000
Prefix 设定objectKey的前缀,前缀是指objectKey包含并以Prefix的值作为开始。
通常与Delimiter配合在查询模拟文件夹中使用。
-
Delimiter 是一个分隔符,用来对objectKey进行分层。
通常与Prefix配合在查询模拟文件夹中使用。
从Prefix开始到第一次出现Delimiter字符之间的objectKey称为:CommonPrefixes。
-
Marker 是一个字符串,用来设定返回结果的起始位置。
设定Marker值之后,返回的Object会从Marker值之后按字母排序开始返回。
-
  • 基本流程

    1. 创建ListObjectsRequest类的实例。
    2. 在ListObjectsRequest中执行setDelimiter/setMarker()/setPrefix()等方法,实现更多的扩展查询操作。
    3. 创建BOSClient类的实例,执行listObjects(listObjectsRequest)。
  • 示例代码

    // 构造ListObjectsRequest请求
    ListObjectsRequest listObjectsRequest = new ListObjectsRequest(<BucketName>);  
    
    // 设置扩展查询参数
    listObjectsRequest.setDelimiter(<Delimiter>);
    listObjectsRequest.setMarker(<Marker>);
    ...   
    ListObjectsResponse listing = client.listObjects(listObjectsRequest);

    说明:上面代码中调用了 listObjects 中的一个重载方法,通过传入 ListObjectsRequest 来完成请求。

  • 完整示例

    示例一:

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.BosObjectSummary;
    import com.baidubce.services.bos.model.ListObjectsRequest;
    import com.baidubce.services.bos.model.ListObjectsResponse;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 构造ListObjectsRequest请求
                    ListObjectsRequest listObjectsRequest = new ListObjectsRequest(<BucketName>); 
    
                    // 设置参数
                    listObjectsRequest.setDelimiter("/");
                    listObjectsRequest.setMarker("123");
                    listObjectsRequest.setMaxKeys(100);
                    listObjectsRequest.setPrefix("fun");
    
                    // 获取指定Bucket下符合上述条件的所有Object信息
                    ListObjectsResponse listing = client.listObjects(listObjectsRequest);
    
                    // 遍历所有Object
                    for (BosObjectSummary objectSummary : listing.getContents()) {
                        System.out.println("ObjectKey: " + objectSummary.getKey());
                    }                	
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                }
            }
        }).start();
    }}

    示例二:使用Nextmarker完整示例。

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.BosObjectSummary;
    import com.baidubce.services.bos.model.ListObjectsRequest;
    import com.baidubce.services.bos.model.ListObjectsResponse;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      new Thread(new Runnable() {
          @Override
          public void run() {
             try {
                BosClientConfiguration config = new BosClientConfiguration();
                config.setCredentials(new DefaultBceCredentials(<AccessKeyId>, <SecretAccessKey>);
                config.setEndpoint(<EndPoint>);
                BosClient client = new BosClient(config);
                ListObjectsRequest listObjectsRequest = new ListObjectsRequest(<BucketName>);
                listObjectsRequest.setMarker("");
                listObjectsRequest.setMaxKeys(20);
                listObjectsRequest.setDelimiter(BceConfig.BOS_DELIMITER);
                ListObjectsResponse listObjectsResponse = client.listObjects(listObjectsRequest);
                String nextMark = "";
                if(listObjectsResponse.isTruncated()){
                   nextMark = listObjectsResponse.getNextMarker();
                }
    
               ListObjectsRequest listObjectsRequest2 = new ListObjectsRequest(<BucketName>);
               listObjectsRequest2.setMarker(nextMark);
               listObjectsRequest2.setMaxKeys(20);
               listObjectsRequest2.setDelimiter(BceConfig.BOS_DELIMITER);
               ListObjectsResponse listing = client.listObjects(listObjectsRequest2);
    
               for (BosObjectSummary objectSummary : listing.getContents()) {
                   System.out.println("ObjectKey: " + objectSummary.getKey());
                }                
    
              } catch (BceServiceException e) {
                System.out.println("Error ErrorCode: " + e.getErrorCode());
                System.out.println("Error RequestId: " + e.getRequestId());
                System.out.println("Error StatusCode: " + e.getStatusCode());
                System.out.println("Error Message: " + e.getMessage());
                System.out.println("Error ErrorType: " + e.getErrorType());
             } catch (BceClientException e) {
                System.out.println("Error Message: " + e.getMessage());
             }
          }
        }).start();
    }}

查询模拟文件夹

由于BOS本身是一个(<Key>,<Value>)的存储系统,所以原则上并不会存在“文件夹”的概念,但您可以通过 DelimiterPrefix 参数的配合进行文件夹功能模拟。

假设Bucket中有5个文件:bos.jpg,fun/,fun/test.jpg,fun/movie/001.avi,fun/movie/007.avi,可以把 “/” 符号作为分隔符模拟文件夹。

递归列出模拟文件夹下所有文件

可以通过设置 Prefix 参数来获取某个模拟文件夹下所有的文件:

// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(<BucketName>);

// 递归列出fun文件夹下的所有文件
listObjectsRequest.setPrefix("fun/");

ListObjectsResponse listing = client.listObjects(listObjectsRequest);

// 遍历所有Object
System.out.println("Objects:");
for (BosObjectSummary objectSummary : listing.getContents()) {
   System.out.println(objectSummary.getKey());
}

输出:

Objects:
fun/
fun/movie/001.avi
fun/movie/007.avi
fun/test.jpg

查看模拟文件夹下的文件和子文件夹

PrefixDelimiter 结合的情况下,可以列出模拟文件夹下的文件和子文件夹:

// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(<BucketName>);

// 指定"/" 为模拟文件夹的分隔符
listObjectsRequest.setDelimiter("/");

// 列出fun文件夹下的所有文件和子文件夹
listObjectsRequest.setPrefix("fun/");

ListObjectsResponse listing = client.listObjects(listObjectsRequest);

// 遍历所有Object
System.out.println("Objects:");
for (BosObjectSummary objectSummary : listing.getContents()) {
   System.out.println(objectSummary.getKey());
}

// 遍历所有CommonPrefix
System.out.println("\nCommonPrefixs:");
for (String commonPrefix : listing.getCommonPrefixes()) {
   System.out.println(commonPrefix);
}

输出:

Objects:
fun/
fun/test.jpg

CommonPrefixs:
fun/movie/

说明:

返回的结果中, Objects 的列表中给出的是fun文件夹下的文件。而 CommonPrefixs 的列表中给出的是fun文件夹下的所有子文件夹。可以看出 fun/movie/001.avifun/movie/007.avi 两个文件并没有被列出来,因为它们属于 fun 文件夹下的 movie 子文件夹下的文件。

获取Object

简单的获取Object

用户可以通过如下代码将Object读取到一个流中。

  • 基本流程

    1. 创建BOSClient类的实例。
    2. 执行BOSClient.getObject()方法,会返回指定的BosObject。
    3. 将BosObject读到流中,然后对流进行操作。
  • 示例代码

    // 获取Object,返回结果为BosObject对象
    BosObject object = client.getObject(<BucketName>, <ObjectKey>);
    
    // 获取ObjectMeta
    ObjectMetadata meta = object.getObjectMetadata();
    
    // 获取Object的输入流
    InputStream objectContent = object.getObjectContent();
    
    // 处理Object
    ...
    
    // 关闭流
    objectContent.close();

    注意:

    • BosObject中包含了Object的各种信息,包含Object所在的Bucket、Object的名称、MetaData以及一个输入流,用户可以通过操作输入流将Object的内容读取到文件或者内存中。
    • ObjectMetadata中包含了Object上传时定义的ETag,Http Header以及自定义的元数据。
    • 通过BosObject的getObjectContent()方法,还可以获取返回Object的输入流,用户可以读取这个输入流来对Object的内容进行操作。
  • 完整示例

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.BosObject;
    import com.baidubce.services.bos.model.ObjectMetadata;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 获取Object,返回结果为BosObject对象
                    BosObject object = client.getObject(<BucketName>, <ObjectKey>);
    
                    // 获取ObjectMeta
                    ObjectMetadata meta = object.getObjectMetadata();
    
                    // 获取Object的输入流
                    InputStream objectContent = object.getObjectContent();
    
                    // 处理Object
                    FileOutputStream fos=new FileOutputStream(android.os.Environment.getExternalStorageDirectory()+"/1/file");  
                    byte[] buffer=new byte[<bufferSize>];  
                    int count=0;  
                    while ((count=objectContent.read(buffer))>=0) {  
                        fos.write(buffer,0,count);  
                    }  
    
                    System.out.println(meta.getETag());
                    System.out.println(meta.getContentLength());
    
                    // 关闭流
                    objectContent.close();
                    fos.close(); 
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
    }}

通过GetObjectRequest获取Object

为了实现更多的功能,可以通过使用GetObjectRequest来获取Object。

  • 基本流程

    1. 创建GetObjectRequest类的实例。
    2. 对GetObjectRequest执行setRange( ),获取Object中所需的字节数据。
    3. 执行client.getObject( )操作。
  • 示例代码

    // 新建GetObjectRequest
    GetObjectRequest getObjectRequest = new GetObjectRequest(<BucketName>, <ObjectKey>);
    
    // 获取0~100字节范围内的数据
    getObjectRequest.setRange(0, 100);
    
    // 获取Object,返回结果为BosObject对象
    BosObject object = client.getObject(getObjectRequest);

    说明:通过getObjectRequest的setRange( )方法可以设置返回Object的范围。用户可以用此功能实现文件的分段下载和断点续传。

获取下载进度

用户可以通过回调函数获取到下载的进度信息。

SDK提供的下载进度回调接口如下,您可以在其中定义在上传过程中您所需要的操作,如更新界面等等。

public interface BceProgressCallback<T extends AbstractBceRequest> {
          // request为下载的请求
          // currentSize为当前下载的大小(单位:byte)
          // totalSize为本次请求需要下载的总大小(单位:byte)
          void onProgress(T request, long currentSize, long totalSize);
  • 示例代码

    GetObjectRequest request = new GetObjectRequest()
            .withBucketName(this.bucketName)
            .withKey(objectKey)
            .withRange(0, 5);
    request.setProgressCallback(new BosProgressCallback<GetObjectRequest>() {
        @Override
        public void onProgress(GetObjectRequest request, long currentSize, long totalSize) {
            Log.e(currentSize + "", totalSize + "");
        }
    });
    InputStream input = this.client.getObject(request).getObjectContent();

    注意: 下载进度接口与上传进度接口有所不同,无法指定每次回调时,下载量增长的片段大小。

下载Object到指定路径

用户可以通过如下代码直接将Object下载到指定路径。

  • 基本流程

    1. 创建GetObjectRequest类的实例。
    2. 执行client.getObject( )操作。
    3. Object可以直接下载到指定路径。
  • 示例代码

    // 新建GetObjectRequest
    GetObjectRequest getObjectRequest = new GetObjectRequest(<BucketName>, <ObjectKey>);
    
    // 下载Object到文件
    ObjectMetadata objectMetadata = client.getObject(getObjectRequest, new File("/path/to/file","w+"));

    说明:当使用上面方法将Object直接下载到指定路径时,方法会返回ObjectMetadata对象。

获取Object的storageClass

Object的storage class属性分为STANDARD(标准存储)、STANDARD_IA(低频存储)、COLD(冷存储)和ARCHIVE(归档存储)。

示例代码

public void getObjectStorageClass(){
  //...
ObjectMetadata meta = client.getObjectMetadata(bucketName, key);
String storageClass = meta.getStorageClass();
}

只获取ObjectMetadata

通过 getObjectMetadata() 方法可以只获取ObjectMetadata而不获取Object的实体。

示例代码

ObjectMetadata objectMetadata = client.getObjectMetadata(<BucketName>, <ObjectKey>);

获取Object的URL

您可以通过如下代码获取指定Object的URL,该功能通常用于您将Object的URL临时分享给其他用户的场景。

  • 基本流程

    1. 创建BOSClient类的实例。
    2. 执行BOSClient.generatePresignedUrl( )方法。
    3. 返回一个Object的URL。
  • 示例代码

    URL url = client.generatePresignedUrl(<BucketName>, <ObjectKey>, <ExpirationInSeconds>);

    说明:ExpirationInSeconds为指定的URL有效时长,时间从当前时间算起,为可选参数,不配置时系统默认值为1800秒。如果要设置为永久不失效的时间,可以将ExpirationInSeconds参数设置为 -1,不可设置为其他负数。

  • 完整示例

    import java.net.URL;
    import android.app.Activity;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    
    public class ExampleActivity extends Activity {
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    //获取Object的URL
                    URL url = client.generatePresignedUrl(<BucketName>, <ObjectKey>, 2000);  
                    Uri uri = Uri.parse(url.toString());
                    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    
                    //执行URL
                    startActivity(intent);
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } 
            }
        }).start();
    }}

Object权限控制

设置Object的访问权限

目前BOS支持两种方式设置ACL。第一种是使用Canned Acl,在PutObjectAcl的时候,通过头域的"x-bce-acl"或者"x-bce-grant-permission'来设置object访问权限,当前可设置的权限包括private和public-read,两种类型的header不可以同时在一个请求中出现。第二种方式是上传一个ACL文件。

详细信息请参考设置Object权限控制

1、通过使用头域的"x-bce-acl"或者"x-bce-grant-permission'来设置object访问权限

  • set object acl 第一种方式(以请求头方式设置)
SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest("yourBucketName","objectKey",CannedAccessControlList.PublicRead);
client.setObjectAcl(setObjectAclRequest);
  • set object acl 第一种方式(以请求头方式设置 xBceGrantRead)
String xBceGrantRead = "id=\"user_id1\""+",id=\"user_id2\"";
SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest();
setObjectAclRequest.withBucketName("yourBucketName");
setObjectAclRequest.withKey("objectKey");
setObjectAclRequest.setxBceGrantRead(xBceGrantRead);
client.setObjectAcl(setObjectAclRequest);
  • set object acl 第一种方式(已请求头方式设置 xBceGrantFullControl)
String xBceGrantFullControl = "id=\"user_id1\""+",id=\"user_id2\"";
SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest();
setObjectAclRequest.withBucketName("yourBucketName");
setObjectAclRequest.withKey("objectKey");
setObjectAclRequest.setxBceGrantFullControl(xBceGrantFullControl);
client.setObjectAcl(setObjectAclRequest);

2、通过setObjectAcl设置object访问权限

  • set object acl 第二种方式(json字符串)
String jsonObjectAcl = "{\"accessControlList\":["+ "{\"grantee\":[{\"id\":\"*\"}], "+ "\"permission\":[\"FULL_CONTROL\"]"+"}]}";

SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest("yourBucketName","objectKey",jsonObjectAcl);

client.setObjectAcl(setObjectAclRequest);
  • set object acl 第二种方式,用户只需指定指定参数即可
List<Grant> grants = new ArrayList<Grant>();
List<Grantee> grantees = new ArrayList<Grantee>();
List<Permission> permissions = new ArrayList<Permission>();

// 授权给特定用户
grantees.add(new Grantee("user_id1"));
grantees.add(new Grantee("user_id2"));
grantees.add(new Grantee("user_id3"));

// 设置权限
permissions.add(Permission.READ);
grants.add(new Grant().withGrantee(grantees).withPermission(permissions));

SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest("yourBucketName","objectKey", grants);
client.setObjectAcl(setObjectAclRequest);

查看Object的权限

如下代码可以查Object的权限:

GetObjectAclRequest getObjectRequest = new GetObjectAclRequest();
getObjectRequest.withBucketName("yourBucketName");
getObjectRequest.withKey("objectKey");
GetObjectAclResponse response = client.getObjectAcl(getObjectRequest);

getObjectAcl方法返回的解析类中可供调用的参数有:

参数 说明
accessControlList 标识Object的权限列表
grantee 标识被授权人
-id 被授权人ID
permission 标识被授权人的权限

删除Object的权限

如下代码可以删除Object的权限:

DeleteObjectAclRequest deleteObjectAclRequest = new DeleteObjectAclRequest("yourBucketName","objectKey");

client.deleteObjectAcl(deleteObjectAclRequest);

删除Object

  • 基本流程

    1. 创建BOSClient类的实例。
    2. 执行BOSClient.deleteObject()方法。
    3. 若操作失败后抛出异常,若成功无返回值。
  • 示例代码

    // 删除Object
    client.deleteObject(BucketName,ObjectKey);   //指定要删除的Object所在Bucket名称和该Object名称
  • 完整示例

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 删除Object
                    client.deleteObject(<BucketName>, <ObjectKey>);   //指定要删除的Object所在Bucket名称和该Object名称
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } 
            }
        }).start();
    }}

拷贝Object

简单拷贝Object

  • 基本流程

    1. 创建BOSClient 类的实例。
    2. 执行BOSClient.copyObject( )方法。
    3. 返回CopyObjectResponse类实例,可通过getETag()/getLastModified()获取eTag和最后修改时间。
  • 示例代码

    // 拷贝Object
    CopyObjectResponse copyObjectResponse = client.copyObject(<SrcBucketName>, <SrcKey>, <DestBucketName>, <DestKey>);  //SrcBucketName, SrcKey为原地址,DestBucketName, DestKey为拷贝到的目的地址
    
    // 打印结果
    System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
  • 完整示例

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.CopyObjectResponse;
    
    public class ExampleActivity extends Activity {
    
    private String srcBucketName = <SrcBucketName>;
    private String srcKey = <SrcKey>;
    
    private String destBucketName = <DestBucketName>;
    private String destKey = <DestKey>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    // 拷贝Object
                    CopyObjectResponse copyObjectResponse = client.copyObject(<SrcBucketName>, <SrcKey>, <DestBucketName>, <DestKey>);
    
                    // 打印结果
                    System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } 
            }
        }).start();
    }}

    说明:copyObject 方法返回一个 CopyObjectResponse 对象,该对象中包含了新Object的ETag和修改时间。

通过CopyObjectRequest拷贝Object

您也可以通过 CopyObjectRequest 实现Object的拷贝。该功能一般用于如下场景:

  • Copy一个Object但重新设置meta。
  • 重置某个现有Object的meta(把Src和Des设置为同一个Object)。
  • 基本流程

    1. 创建CopyObjectRequest类的实例,传入<SrcBucketName>, <SrcKey>, <DestBucketName>, <DestKey>参数。
    2. 创建ObjectMetadata类的实例。
    3. 返回CopyObjectResponse类实例,可通过getETag()/getLastModified()获取eTag和最后修改时间。
  • 示例代码

    // 创建CopyObjectRequest对象
    CopyObjectRequest copyObjectRequest = new CopyObjectRequest(<SrcBucketName>, <SrcKey>, <DestBucketName>, <DestKey>);
    
    // 设置新的Metadata
    Map<String, String> userMetadata = new HashMap<String, String>();
    userMetadata.put(<UserMetaKey>,<UserMetaValue>);
    meta.setUserMetadata(userMetadata);
    copyObjectRequest.setNewObjectMetadata(meta);
    
    // 复制Object
    CopyObjectResponse copyObjectResponse = client.copyObject(copyObjectRequest);
    
    System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());

    说明:CopyObjectRequest 允许用户修改目的Object的ObjectMeta,同时也提供 MatchingETagConstraints 参数的设定。

Object的分块上传

分块上传的场景

除了通过putObject()方法上传文件到BOS以外,BOS还提供了另外一种上传模式:分块上传(Multipart Upload)。用户可以在如下的应用场景内(但不仅限于此),使用分块上传模式,如:

  • 需要支持断点上传。
  • 上传超过5GB大小的文件。
  • 网络条件较差,和BOS的服务器之间的连接经常断开。
  • 需要流式地上传文件。
  • 上传文件之前,无法确定上传文件的大小。

Multipart Upload分块上传流程

假设有一个文件,本地路径为 /path/to/file.zip ,由于文件比较大,使用分块上传其传输到BOS中。

  • 基本流程

    1. 初始化Multipart Upload。
    2. 上传分块。
    3. 完成分块上传。

初始化Multipart Upload

使用 initiateMultipartUpload 方法来初始化一个分块上传事件:

  • 示例代码

    // 开始Multipart Upload
    InitiateMultipartUploadRequest initiateMultipartUploadRequest =
          new InitiateMultipartUploadRequest(<BucketName>, <ObjectKey>);
    InitiateMultipartUploadResponse initiateMultipartUploadResponse =
          client.initiateMultipartUpload(initiateMultipartUploadRequest);
    
    // 打印UploadId
    System.out.println("UploadId: " + initiateMultipartUploadResponse.getUploadId());

    说明:initiateMultipartUpload 的返回结果中含有 UploadId ,它是区分分块上传事件的唯一标识,在后面的操作中,我们将用到它。

上传分块

将文件分块上传。

  • 示例代码

    // 设置每块为 5MB
    final long partSize = 1024 * 1024 * 5L;
    
    File partFile = new File("/path/to/file.zip");
    
    // 计算分块数目
    int partCount = (int) (partFile.length() / partSize);
    if (partFile.length() % partSize != 0) {
        partCount++;
    }
    // 新建一个List保存每个分块上传后的ETag和PartNumber
    List<PartETag> partETags = new ArrayList<PartETag>();
    // 获取文件流
    FileInputStream fis = new FileInputStream(partFile);
    for (int i = 0; i < partCount; i++) {
    
        // 计算每个分块的大小
        long skipBytes = partSize * i;
        long size = partSize < partFile.length() - skipBytes ?
                  partSize : partFile.length() - skipBytes;
    
        byte[] buf = new byte[(int)size];
        int offset = 0;
        while (true) {
            int byteRead = fis.read(buf, offset, (int)size);
            offset += byteRead;
            if (byteRead < 0 || offset >= size) {
               break;
            }
        }
        ByteArrayInputStream bufStream = new ByteArrayInputStream(buf);
    
        // 创建UploadPartRequest,上传分块
        UploadPartRequest uploadPartRequest = new UploadPartRequest();
        uploadPartRequest.setBucketName(bucketName);
        uploadPartRequest.setKey(objectkey);
        uploadPartRequest.setUploadId(initiateMultipartUploadResponse.getUploadId());
        uploadPartRequest.setInputStream(bufStream);
        uploadPartRequest.setPartSize(size);
        uploadPartRequest.setPartNumber(i + 1);
        // 上传进度回调
        uploadPartRequest.setProgressCallback(new BosProgressCallback<UploadPartRequest>() {
            @Override
            public void onProgress(UploadPartRequest request, long currentSize, long totalSize) {
                Log.e(currentSize + "", totalSize + "");
            }
        });
    
        UploadPartResponse uploadPartResponse = client.uploadPart(uploadPartRequest);
    
        // 将返回的PartETag保存到List中。
        partETags.add(uploadPartResponse.getPartETag());
    
        System.out.println(uploadPartResponse.getPartETag());
      }
      // 关闭文件
      fis.close();

    注意:上面代码的核心是调用 UploadPart 方法来上传每一个分块,但是要注意以下几点:

    • UploadPart 方法要求Part大小是1MB的整数倍或大于5MB。但是Upload Part接口并不会立即校验上传Part的大小;只有当Complete Multipart Upload的时候才会校验。
    • 为了保证数据在网络传输过程中不出现错误,建议您在UploadPart后,使用每个分块BOS返回的Content-MD5值分别验证已上传分块数据的正确性。当所有分块数据合成一个Object后,不再含MD5值。
    • Part号码的范围是1~10000。如果超出这个范围,BOS将返回InvalidArgument的错误码。
    • 每次上传Part时都要把流定位到此次上传块开头所对应的位置。
    • 每次上传Part之后,BOS的返回结果会包含一个 PartETag 对象,它是上传块的ETag与块编号(PartNumber)的组合,在后续完成分块上传的步骤中会用到它,因此需要将其保存起来。一般来讲这些 PartETag 对象将被保存到List中。
    • 进度回调接口的使用可以参考“获取上传进度”一章。

完成分块上传

  • 示例代码

    CompleteMultipartUploadRequest completeMultipartUploadRequest =
          new CompleteMultipartUploadRequest(<BucketName>, <ObjectKey>, 
                initiateMultipartUploadResponse.getUploadId(), partETags);
    
    // 完成分块上传
    CompleteMultipartUploadResponse completeMultipartUploadResponse =
          client.completeMultipartUpload(completeMultipartUploadRequest);
    
    // 打印Object的ETag
    System.out.println(completeMultipartUploadResponse.getETag());

    说明:上面代码中的 partETags 是第二步中保存的partETag的列表,BOS收到用户提交的Part列表后,会逐一验证每个数据Part的有效性。当所有的数据Part验证通过后,BOS将把这些数据part组合成一个完整的Object。

  • 完整示例

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import org.json.JSONException;
    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.CompleteMultipartUploadRequest;
    import com.baidubce.services.bos.model.CompleteMultipartUploadResponse;
    import com.baidubce.services.bos.model.InitiateMultipartUploadRequest;
    import com.baidubce.services.bos.model.InitiateMultipartUploadResponse;
    import com.baidubce.services.bos.model.PartETag;
    import com.baidubce.services.bos.model.UploadPartRequest;
    import com.baidubce.services.bos.model.UploadPartResponse;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                  BosClientConfiguration config = new BosClientConfiguration();
                  config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                  config.setEndpoint(<EndPoint>);
                  BosClient client = new BosClient(config);
    
                  // 开始Multipart Upload
                  InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(<BucketName>, <ObjectKey>);
                  InitiateMultipartUploadResponse initiateMultipartUploadResponse =
                            client.initiateMultipartUpload(initiateMultipartUploadRequest);
    
                  // 打印UploadId
                  System.out.println("UploadId: " + initiateMultipartUploadResponse.getUploadId());
    
                  // 设置每块为 5MB
                  final long partSize = 1024 * 1024 * 5L;
    
                  File partFile = new File("/path/to/file.zip");
    
                  // 计算分块数目
                  int partCount = (int) (partFile.length() / partSize);
                  if (partFile.length() % partSize != 0) {
                      partCount++;
                  }
    
                  // 新建一个List保存每个分块上传后的ETag和PartNumber
                  List<PartETag> partETags = new ArrayList<PartETag>();
    
                  // 获取文件流
                  FileInputStream fis = new FileInputStream(partFile);
                  for (int i = 0; i < partCount; i++) {                       
    
                      // 计算每个分块的大小
                      long skipBytes = partSize * i;
                      long size = partSize < partFile.length() - skipBytes ?
                              partSize : partFile.length() - skipBytes;
    
                      byte[] buf = new byte[(int)size];
                      int offset = 0;
                      while (true) {
                          int byteRead = fis.read(buf, offset, (int)size);
                          offset += byteRead;
                          if (byteRead < 0 || offset >= size) {
                              break;
                          }
                      }
                      ByteArrayInputStream bufStream = new ByteArrayInputStream(buf);
    
                      // 创建UploadPartRequest,上传分块
                      UploadPartRequest uploadPartRequest = new UploadPartRequest();
                      uploadPartRequest.setBucketName(<BucketName>);
                      uploadPartRequest.setKey(<ObjectKey>);
                      uploadPartRequest.setUploadId(initiateMultipartUploadResponse.getUploadId());
                      uploadPartRequest.setInputStream(fis);
                      uploadPartRequest.setPartSize(size);
                      uploadPartRequest.setPartNumber(i + 1);
                      UploadPartResponse uploadPartResponse = client.uploadPart(uploadPartRequest);
    
                      // 将返回的PartETag保存到List中。
                      partETags.add(uploadPartResponse.getPartETag());
    
                      System.out.println(uploadPartResponse.getPartETag());                                         
                  }
                  // 关闭文件
                  fis.close();
    
                  CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(<BucketName>, <ObjectKey>, initiateMultipartUploadResponse.getUploadId(), partETags);
    
                  // 完成分块上传
                  CompleteMultipartUploadResponse completeMultipartUploadResponse =
                          client.completeMultipartUpload(completeMultipartUploadRequest);
    
                  // 打印Object的ETag
                  System.out.println(completeMultipartUploadResponse.getETag());
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 
            }
        }).start();
    }}

取消分块上传

用户可以使用abortMultipartUpload方法取消分块上传。

  • 示例代码

    AbortMultipartUploadRequest abortMultipartUploadRequest =
        new AbortMultipartUploadRequest(<BucketName>, <ObjectKey>, <UploadId>);
    
    // 取消分块上传
    client.abortMultipartUpload(abortMultipartUploadRequest);

获取未完成的分块上传

用户可以使用 listMultipartUploads 方法获取Bucket内未完成的分块上传事件。

  • 基本流程

    1. 创建listMultipartUploadsRequest类的实例,传入<BucketName>参数。
    2. 创建BOSClient类的实例,执行BOSClient.listMultipartUploads( )方法。
    3. listMultipartUploads()返回所有已上传part的信息。
  • 示例代码

    ListMultipartUploadsRequest listMultipartUploadsRequest = 
        new ListMultipartUploadsRequest(<BucketName>);
    
    // 获取Bucket内所有上传事件
    ListMultipartUploadsResponse list = client.listMultipartUploads(listMultipartUploadsRequest);// 遍历所有上传事件
    for (MultipartUploadSummary multipartUpload : list.getMultipartUploads()) {
        System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId());
    }

    注意:

    • 默认情况下,如果Bucket中的分块上传事件的数目大于1000,则只会返回1000个Object,并且返回结果中IsTruncated的值为True,同时返回NextKeyMarker作为下次读取的起点。
    • 若想获取更多分块上传事件,可以使用KeyMarker参数分次读取。
  • 完整示例

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.ListMultipartUploadsRequest;
    import com.baidubce.services.bos.model.ListMultipartUploadsResponse;
    import com.baidubce.services.bos.model.MultipartUploadSummary;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    ListMultipartUploadsRequest listMultipartUploadsRequest = 
                            new ListMultipartUploadsRequest(<BucketName>);
    
                        // 获取Bucket内所有上传事件
                    ListMultipartUploadsResponse listing = client.listMultipartUploads(listMultipartUploadsRequest);
    
                     // 遍历所有上传事件
                     for (MultipartUploadSummary multipartUpload : listing.getMultipartUploads()) {
                         System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId());
                     }
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                    System.out.println("Error Message: " + e.getMessage());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } 
            }
        }).start();
    }}

获取所有已上传的分块信息

用户可以使用 listParts 方法获取某个上传事件中所有已上传的块。

  • 基本流程

    1. 创建ListPartsRequest类的实例,传入<BucketName>,<ObjectKey>, <UploadId>参数。
    2. 创建BOSClient类的实例,执行BOSClient.listParts( )方法。
    3. listParts()返回所有已上传part的信息。
  • 示例代码

    ListPartsRequest listPartsRequest = new ListPartsRequest(<BucketName>, <ObjectKey>, <UploadId>);// 获取上传的所有Part信息
    ListPartsResponse partListing = client.listParts(listPartsRequest);// 遍历所有Part
    for (PartSummary part : partListing.getParts()) {
        System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag());
    }

    注意:

    • 默认情况下,如果Bucket中的分块上传事件的数目大于1000,则只会返回1000个Object,并且返回结果中IsTruncated的值为True,同时返回NextPartNumberMarker作为下次读取的起点。
    • 若想获取更多已上传的分块信息,可以使用PartNumberMarker参数分次读取。
  • 完整示例

    import android.app.Activity;
    import android.os.Bundle;
    import com.baidubce.BceClientException;
    import com.baidubce.BceServiceException;
    import com.baidubce.auth.DefaultBceCredentials;
    import com.baidubce.demo.R;
    import com.baidubce.services.bos.BosClient;
    import com.baidubce.services.bos.BosClientConfiguration;
    import com.baidubce.services.bos.model.ListPartsRequest;
    import com.baidubce.services.bos.model.ListPartsResponse;
    import com.baidubce.services.bos.model.PartSummary;
    
    public class ExampleActivity extends Activity {
    
    private String bucketName = <BucketName>;
    private String objectKey = <ObjectKey>;
    private String uploadId = <UploadId>;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BosClientConfiguration config = new BosClientConfiguration();
                    config.setCredentials(new DefaultBceCredentials(<AccessKeyID>, <SecretAccessKey>));
                    config.setEndpoint(<EndPoint>);
                    BosClient client = new BosClient(config);
    
                    ListPartsRequest listPartsRequest = new ListPartsRequest(<BucketName>, <ObjectKey>, <UploadId>);
                    listPartsRequest.setMaxParts(100);
                    listPartsRequest.setPartNumberMarker(50);
    
                     // 获取上传的所有Part信息
                     ListPartsResponse partListing = client.listParts(listPartsRequest);
    
                     // 遍历所有Part
                     for (PartSummary part : partListing.getParts()) {
                         System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag());
                     }
    
                } catch (BceServiceException e) {
                    System.out.println("Error ErrorCode: " + e.getErrorCode());
                    System.out.println("Error RequestId: " + e.getRequestId());
                    System.out.println("Error StatusCode: " + e.getStatusCode());
                    System.out.println("Error ErrorType: " + e.getErrorType());
                    System.out.println("Error Message: " + e.getMessage());
                } catch (BceClientException e) {
                    System.out.println("Error Message: " + e.getMessage());
                } 
            }
        }).start();
    }}

封装分块上传

在Android SDK中,Bos为用户提供了putSuperObjectFromFile接口,它对分块上传涉及到的initiateMultipartUpload、UploadPart、completeMultipartUpload三个方法进行封装,用户只需调用该接口即可完成分块上传,同时,支持进度同步回调。

  • 简单示例:

    File file = new File("/path/to/file.zip");
    PutSuperObjectRequest request = new PutSuperObjectRequest(bucketName, objectKey, file);
    bosClient.putSuperObjectFromFile(request);
  • 示例:设置分块大小为2MB,线程数为4,并且每1024个byte同步进度回调

    BosClientConfiguration config=new BosClientConfiguration();
    config.setUploadSegmentPart(1024);
    File file = new File("/path/to/file.zip");
    PutSuperObjectRequest request = new PutSuperObjectRequest(bucketName, objectKey,
                                                              file, 1024 * 1024 * 2L, 4);
    request.setProgressCallback(new BosProgressCallback<PutSuperObjectRequest>() {
        @Override
        public void onProgress(PutSuperObjectRequest request, long currentSize, long totalSize) {
            Log.e(currentSize + "", totalSize + "");
        }
    });
    bosClient.putSuperObjectFromFile(request);

注意:

  • 默认情况下,分块大小是5MB,线程数是5,进度回调周期是每2048个byte。
  • 若一个大文件耗时很长,用户想结束分块上传,可调用PutSuperObjectRequest中的cancel()方法。