对象存储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

    • 基本流程

      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()方法。
    上一篇
    Bucket管理
    下一篇
    日志