须知
开发过程中,您有任何问题可以在github上提交issue,或者在华为云对象存储服务论 坛中发帖求助。接口参考文档详细介绍了每个接口的参数和使用方法。
对于较大文件上传,可以切分成段上传。用户可以在如下的应用场景内(但不仅限于 此),使用分段上传的模式:
● 上传超过100MB大小的文件。
● 网络条件较差,和OBS服务端之间的链接经常断开。
● 上传前无法确定将要上传文件的大小。
使用分段上传具有以下优势:
● 提高吞吐量—您可以并行上传段以提高吞吐量。
● 从任何网络问题中快速恢复—较小的段大小可以将由于网络错误而需重启失败的 上传所产生的影响降至最低。
● 暂停和恢复对象上传—您可以随时上传对象段。启动多段上传后,不存在过期期 限;您必须显式地完成或取消多段上传任务。
● 在得知最终对象大小之前开始上传—您可以在创建对象的同时上传对象。
分段上传分为如下3个步骤:
步骤1 初始化分段上传任务(ObsClient.initiateMultipartUpload)。
步骤2 逐个或并行上传段(ObsClient.uploadPart)。
步骤3 合并段(ObsClient.completeMultipartUpload)或取消分段上传任务 (ObsClient.abortMultipartUpload)。
----结束
初始化分段上传任务
使用分段上传方式传输数据前,必须先通知OBS初始化一个分段上传任务。该操作会 返回一个OBS服务端创建的全局唯一标识(Upload ID),用于标识本次分段上传任 务。您可以根据这个唯一标识来发起相关的操作,如取消分段上传任务、列举分段上 传任务、列举已上传的段等。
您可以通过ObsClient.initiateMultipartUpload初始化一个分段上传任务:
该接口可设置的参数如下:
Java SDK 开发指南 9 上传对象
参数 作用 OBS Java SDK对应方法 bucketName 桶名。 initiateMultipartUpload.s
etBucketName
objectKey 设置分段上传任务所属的对象名 initiateMultipartUpload.s etObjectKey
expires 设置分段上传任务最终生成对象的过
期时间,正整数。 initiateMultipartUpload.s etExpires
metadata 设置对象属性,支持content-type,
用户自定义元数据 initiateMultipartUpload.s etMetadata
isEncodeHeade
rs 是否自动编码请求头 initiateMultipartUpload.s etIsEncodeHeaders
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest("bucketname",
"objectname");
ObjectMetadata metadata = new ObjectMetadata();
metadata.addUserMetadata("property", "property-value");
metadata.setContentType("text/plain");
request.setMetadata(metadata);
InitiateMultipartUploadResult result = obsClient.initiateMultipartUpload(request);
String uploadId = result.getUploadId();
System.out.println("\t" + uploadId);
说明
● 用InitiateMultipartUploadRequest指定上传对象的名称和所属桶。
● 在InitiateMultipartUploadRequest中,您可以设置对象MIME类型、对象存储类型、对象自 定义元数据等对象属性。
● InitiateMultipartUploadResult.getUploadId返回分段上传任务的全局唯一标识(Upload ID),在后面的操作中将用到它。
● 由于 HTTP 编码规范限制,无法发送非 ASCII 码字符,SDK 会在发送请求时对您头域中的中 文汉字进行 url 编码,发送编码后数据。如您设置的值 content-disposition 为 ”attachment;
filename="中文.txt"”,则对象元数据中存储的信息为”attachment;
filename="%E4%B8%AD%E6%96%87.txt"”。使用浏览器访问时浏览器将会自动解码。
● 如若不需要 SDK 帮您编码,可以调用
InitiateMultipartUploadRequest.setIsEncodeHeaders(false) 关闭自动编码。
上传段
初始化一个分段上传任务之后,可以根据指定的对象名和Upload ID来分段上传数据。
每一个上传的段都有一个标识它的号码——分段号(Part Number,范围是
1~10000)。对于同一个Upload ID,该分段号不但唯一标识这一段数据,也标识了这 段数据在整个对象内的相对位置。如果您用同一个分段号上传了新的数据,那么OBS 上已有的这个段号的数据将被覆盖。除了最后一段以外,其他段的大小范围是
100KB~5GB;最后段大小范围是0~5GB。每个段不需要按顺序上传,甚至可以在不同 进程、不同机器上上传,OBS会按照分段号排序组成最终对象。
Java SDK 开发指南 9 上传对象
您可以通过ObsClient.uploadPart上传段:
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
List<PartEtag> partEtags = new ArrayList<PartEtag>();
// 上传第一段
UploadPartRequest request = new UploadPartRequest("bucketname", "objectname");
// 设置Upload ID
request.setUploadId(uploadId);
// 设置分段号,范围是1~10000,
request.setPartNumber(1);
// 设置将要上传的大文件
request.setFile(new File("localfile"));
// 设置分段大小
request.setPartSize(5 * 1024 * 1024L);
UploadPartResult result = obsClient.uploadPart(request);
partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));
// 上传第二段
request = new UploadPartRequest("bucketname", "objectname");
// 设置Upload ID
request.setUploadId(uploadId);
// 设置分段号
request.setPartNumber(2);
// 设置将要上传的大文件
request.setFile(new File("localfile"));
// 设置第二段的段偏移量
request.setOffset(5 * 1024 * 1024L);
// 设置分段大小
request.setPartSize(5 * 1024 * 1024L);
result = obsClient.uploadPart(request);
partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));
说明
● 上传段接口要求除最后一段以外,其他的段大小都要大于100KB。但是上传段接口并不会立 即校验上传段的大小(因为不知道是否为最后一块);只有调用合并段接口时才会校验。
● OBS会将服务端收到段数据的ETag值(段数据的MD5值)返回给用户。
● 为了保证数据在网络传输过程中不出现错误,可以通过设置
UploadPartRequest.setAttachMd5为true来让SDK自动计算每段数据的MD5值(仅在数据源 为本地文件时有效),并放到Content-MD5请求头中;OBS服务端会计算上传数据的MD5值 与SDK计算的MD5值比较,保证数据完整性。
● 可以通过UploadPartRequest.setContentMd5直接设置上传数据的MD5值,提供给OBS服务 端用于校验数据完整性。如果设置了该值,UploadPartRequest.setAttachMd5参数会被忽 略。
● 分段号的范围是1~10000。如果超出这个范围,OBS将返回400 Bad Request错误。
● OBS 3.0的桶支持最小段的大小为100KB,OBS 2.0的桶支持最小段的大小为5MB。
合并段
参数 作用 OBS Java SDK对应方法 bucketName 桶名。 completeMultipartUploa
d.setBucketName
objectKey 设置分段上传任务所属的对象名 completeMultipartUploa d.setObjectKey
uploadId 设置分段上传任务的ID号 completeMultipartUploa d.setUploadId
partEtag 设置待合并的段列表 completeMultipartUploa d.setPartEtag
您可以通过ObsClient.completeMultipartUpload合并段:
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
List<PartEtag> partEtags = new ArrayList<PartEtag>();
// 第一段
PartEtag part1 = new PartEtag();
part1.setPartNumber(1);
part1.seteTag("etag1");
partEtags.add(part1);
// 第二段
PartEtag part2 = new PartEtag();
part2.setPartNumber(2);
part2.setEtag("etag2");
partEtags.add(part2);
CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest("bucketname",
"objectname", uploadId, partEtags);
obsClient.completeMultipartUpload(request);
说明
● 上面代码中的 partEtags是进行上传段后保存的分段号和分段ETag值的列表。
● 分段可以是不连续的。
并发分段上传
分段上传的主要目的是解决大文件上传或网络条件较差的情况。下面的示例代码展示 了如何使用分段上传并发上传大文件:
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
final String bucketName = "bucketname";
final String objectKey = "objectname";
// 创建ObsClient实例
final ObsClient obsClient = new ObsClient(ak, sk, endPoint);
// 初始化线程池
ExecutorService executorService = Executors.newFixedThreadPool(20);
Java SDK 开发指南 9 上传对象
final File largeFile = new File("localfile");
// 初始化分段上传任务
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectKey);
InitiateMultipartUploadResult result = obsClient.initiateMultipartUpload(request);
final String uploadId = result.getUploadId();
System.out.println("\t"+ uploadId + "\n");
// 每段上传100MB
long partSize = 100 * 1024 * 1024L;
long fileSize = largeFile.length();
// 计算需要上传的段数
long partCount = fileSize % partSize == 0 ? fileSize / partSize : fileSize / partSize + 1;
final List<PartEtag> partEtags = Collections.synchronizedList(new ArrayList<PartEtag>());
// 执行并发上传段
executorService.execute(new Runnable() {
@Override public void run() {
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setObjectKey(objectKey);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setFile(largeFile);
uploadPartRequest.setPartSize(currPartSize);
uploadPartRequest.setOffset(offset);
uploadPartRequest.setPartNumber(partNumber);
partEtags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
}
while (!executorService.isTerminated()) { try
{
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
e.printStackTrace();
} }
Java SDK 开发指南 9 上传对象
// 合并段
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId, partEtags);
obsClient.completeMultipartUpload(completeMultipartUploadRequest);
说明
大文件分段上传时,使用UploadPartRequest.setOffset和UploadPartRequest.setPartSize来设 置每段的起始结束位置。
取消分段上传任务
分段上传任务可以被取消,当一个分段上传任务被取消后,就不能再使用其Upload ID 做任何操作,已经上传段也会被OBS删除。
采用分段上传方式上传对象过程中或上传对象失败后会在桶内产生段,这些段会占用 您的存储空间,您可以通过取消该分段上传任务来清理掉不需要的段,节约存储空 间。
您可以通过ObsClient.abortMultipartUpload取消分段上传任务:
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
AbortMultipartUploadRequest request = new AbortMultipartUploadRequest("bucketname", "objectname", uploadId);
bucketName 分段上传任务所属的桶名。 ListPartsRequest.setBuck etName
key 分段上传任务所属的对象名。 ListPartsRequest.setKey uploadId 分段上传任务全局唯一标识,
从ObsClient.initiateMultipartUpl oad返回的结果获取。
ListPartsRequest.setUplo adId
maxParts 表示列举已上传的段返回结果 最大段数目,即分页时每一页 中段数目。
ListPartsRequest.setMaxP arts
partNumberMarker 表示待列出段的起始位置,只 有Part Number大于该参数的段 会被列出。
ListPartsRequest.setPart NumberMarker
Java SDK 开发指南 9 上传对象
● 简单列举
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
//列举已上传的段,其中uploadId来自于initiateMultipartUpload
ListPartsRequest request = new ListPartsRequest("bucketname", "objectname");
request.setUploadId(uploadId);
ListPartsResult result = obsClient.listParts(request);
for(Multipart part : result.getMultipartList()){
// 分段号,上传时候指定
System.out.println("\t"+part.getPartNumber());
// 段数据大小
System.out.println("\t"+part.getSize());
// 分段的ETag值
System.out.println("\t"+part.getEtag());
// 段的最后上传时间
System.out.println("\t"+part.getLastModified());
}
说明
● 列举段至多返回1000个段信息,如果指定的Upload ID包含的段数量大于1000,则返回结果 中ListPartsResult.isTruncated为true表明本次没有返回全部段,并可通过
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
// 列举所有已上传的段,其中uploadId来自于initiateMultipartUpload ListPartsRequest request = new ListPartsRequest("bucketname", "objectname");
request.setUploadId(uploadId);
ListPartsResult result;
do{ result = obsClient.listParts(request);
for(Multipart part : result.getMultipartList()){
// 分段号,上传时候指定
System.out.println("\t"+part.getPartNumber());
// 段数据大小
System.out.println("\t"+part.getSize());
// 分段的ETag值
System.out.println("\t"+part.getEtag());
// 段的最后上传时间
System.out.println("\t"+part.getLastModified());
}
request.setPartNumberMarker(Integer.parseInt(result.getNextPartNumberMarker()));
}while(result.isTruncated());
列举分段上传任务
您可以通过ObsClient.listMultipartUploads列举分段上传任务。列举分段上传任务可 设置的参数如下:
Java SDK 开发指南 9 上传对象
参数 作用 OBS Java SDK对应方法 bucketName 桶名。 ListMultipartUploadsReq
uest.setBucketName prefix 限定返回的分段上传任务中的对象名
必须带有prefix前缀。 ListMultipartUploadsReq uest.setPrefix
delimiter 用于对分段上传任务中的对象名进行 分组的字符。对于对象名中包含
maxUploads 列举分段上传任务的最大数目,取值 范围为1~1000,当超出范围时,按 照默认的1000进行处理。
ListMultipartUploadsReq uest.setMaxUploads
keyMarker 表示列举时返回指定的keyMarker之
后的分段上传任务。 ListMultipartUploadsReq uest.setKeyMarker uploadIdMarke
r 只有与keyMarker参数一起使用时才 有意义,用于指定返回结果的起始位
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
ListMultipartUploadsRequest request = new ListMultipartUploadsRequest("bucketname");
MultipartUploadListing result = obsClient.listMultipartUploads(request);
for(MultipartUpload upload : result.getMultipartTaskList()){
System.out.println("\t" + upload.getUploadId());
System.out.println("\t" + upload.getObjectKey());
System.out.println("\t" + upload.getInitiatedDate());
}
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
Java SDK 开发指南 9 上传对象
String uploadId = "upload id from initiateMultipartUpload";
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
ListMultipartUploadsRequest request = new ListMultipartUploadsRequest("bucketname");
MultipartUploadListing result;
do{ result = obsClient.listMultipartUploads(request);
for(MultipartUpload upload : result.getMultipartTaskList()){
System.out.println("\t" + upload.getUploadId());
System.out.println("\t" + upload.getObjectKey());
System.out.println("\t" + upload.getInitiatedDate());
}
request.setKeyMarker(result.getNextKeyMarker());
request.setUploadIdMarker(result.getNextUploadIdMarker());
}while(result.isTruncated());