Object管理
上传Object
最简单的上传
-
基本流程
- 创建BOSClient 类的实例。
- 调用BOSClient.putObject()方法,可以通过如下四种方式上传Object:文件、数据流、二进制串和字符串的形式。
- 对返回的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。
-
基本流程
- 创建ObjectMetadata类的实例。
- 执行setContentLength()/setContentType()等方法对Http Header进行设定。
- 将设定后的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进行描述。
-
基本流程
- 创建ObjectMetadata类的实例。
- 执行addUserMetadata()方法对Http Header进行自定义元数据。
- 将设定后的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列表。
-
基本流程
- 创建BOSClient类的实例。
- 执行BOSClient.listObjects(bucketName)方法,会返回ListObjectsResponse类的实例。
- 对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值之后按字母排序开始返回。 |
- |
-
基本流程
- 创建ListObjectsRequest类的实例。
- 在ListObjectsRequest中执行setDelimiter/setMarker()/setPrefix()等方法,实现更多的扩展查询操作。
- 创建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>
)的存储系统,所以原则上并不会存在“文件夹”的概念,但您可以通过 Delimiter
和 Prefix
参数的配合进行文件夹功能模拟。
假设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
查看模拟文件夹下的文件和子文件夹
在 Prefix
和 Delimiter
结合的情况下,可以列出模拟文件夹下的文件和子文件夹:
// 构造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.avi
,fun/movie/007.avi
两个文件并没有被列出来,因为它们属于fun
文件夹下的movie
子文件夹下的文件。
获取Object
简单的获取Object
用户可以通过如下代码将Object读取到一个流中。
-
基本流程
- 创建BOSClient类的实例。
- 执行BOSClient.getObject()方法,会返回指定的BosObject。
- 将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。
-
基本流程
- 创建GetObjectRequest类的实例。
- 对GetObjectRequest执行setRange( ),获取Object中所需的字节数据。
- 执行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下载到指定路径。
-
基本流程
- 创建GetObjectRequest类的实例。
- 执行client.getObject( )操作。
- 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临时分享给其他用户的场景。
-
基本流程
- 创建BOSClient类的实例。
- 执行BOSClient.generatePresignedUrl( )方法。
- 返回一个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
-
基本流程
- 创建BOSClient类的实例。
- 执行BOSClient.deleteObject()方法。
- 若操作失败后抛出异常,若成功无返回值。
-
示例代码
// 删除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
-
基本流程
- 创建BOSClient 类的实例。
- 执行BOSClient.copyObject( )方法。
- 返回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)。
-
基本流程
- 创建CopyObjectRequest类的实例,传入
<SrcBucketName>
,<SrcKey>
,<DestBucketName>
,<DestKey>
参数。 - 创建ObjectMetadata类的实例。
- 返回CopyObjectResponse类实例,可通过getETag()/getLastModified()获取eTag和最后修改时间。
- 创建CopyObjectRequest类的实例,传入
-
示例代码
// 创建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中。
-
基本流程
- 初始化Multipart Upload。
- 上传分块。
- 完成分块上传。
初始化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内未完成的分块上传事件。
-
基本流程
- 创建listMultipartUploadsRequest类的实例,传入
<BucketName>
参数。 - 创建BOSClient类的实例,执行BOSClient.listMultipartUploads( )方法。
- listMultipartUploads()返回所有已上传part的信息。
- 创建listMultipartUploadsRequest类的实例,传入
-
示例代码
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
方法获取某个上传事件中所有已上传的块。
-
基本流程
- 创建ListPartsRequest类的实例,传入
<BucketName>
,<ObjectKey>
,<UploadId>
参数。 - 创建BOSClient类的实例,执行BOSClient.listParts( )方法。
- listParts()返回所有已上传part的信息。
- 创建ListPartsRequest类的实例,传入
-
示例代码
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()方法。