OSS JAVA SDK

安装OSS JAVA SDK

直接在Eclipse中使用JAR包

步骤以下:php

  • 在官方网站下载 Open Service Java SDK 。
  • 解压文件。
  • 将解压后文件夹中的文件: aliyun-openservice-<versionId>.jar 以及lib文件夹下的全部文件拷贝到你的工程文件夹中。
  • 在Eclipse右键工程 -> Properties -> Java Build Path -> Add JARs 。
  • 选择你拷贝的全部JAR文件。

通过上面几步以后,你就能够在工程中使用OSS JAVA SDK了。html

在Maven工程中使用SDK

在Maven工程中使用JAVA SDK十分简单,只要在在pom.xml文件中加入依赖就能够了。java

在 dependencies 标签内加入以下内容:python

<dependency>
    <groupId>com.aliyun.openservices</groupId> <artifactId>aliyun-openservices</artifactId> <version>1.0.10</version> </dependency> 

version为版本号,随着版本更新可能有变更。api

 

快速入门

在这一章里,您将学到如何用OSS Java SDK完成一些基本的操做。浏览器

Step 1. 初始化一个OSSClient

OSSClient是与OSS服务交互的客户端,SDK的OSS操做都是经过OSSClient完成的。服务器

下面代码新建了一个OSSClient:网络

import com.aliyun.openservices.oss.OSSClient; public class Sample { public static void main(String[] args) { String accessKeyId = "<key>"; String accessKeySecret = "<secret>"; // 初始化一个OSSClient OSSClient client = new OSSClient(accessKeyId, accessKeySecret); // 下面是一些调用代码... ... } } 

在上面代码中,变量 accessKeyId 与 accessKeySecret 是由系统分配给用户的,称为ID对,用于标识用户,为访问OSS作签名验证。eclipse

关于OSSClient的详细介绍,参见 OSSClient 。maven

Step 2. 新建Bucket

Bucket是OSS上的命名空间,至关于数据的容器,能够存储若干数据实体(Object)。

你能够按照下面的代码新建一个Bucket:

public void createBucket(String bucketName) { // 初始化OSSClient OSSClient client = ...; // 新建一个Bucket client.createBucket(bucketName); } 

因为Bucket的名字是全局惟一的,因此尽可能保证你的 bucketName 不与别人重复。

关于Bucket的命名规范,参见 Bucket命名规范

Step 3. 上传Object

Object是OSS中最基本的数据单元,你能够把它简单地理解为文件,用下面代码能够实现一个Object的上传:

public void putObject(String bucketName, String key, String filePath) throws FileNotFoundException { // 初始化OSSClient OSSClient client = ...; // 获取指定文件的输入流 File file = new File(filePath); InputStream content = new FileInputStream(file); // 建立上传Object的Metadata ObjectMetadata meta = new ObjectMetadata(); // 必须设置ContentLength meta.setContentLength(file.length()); // 上传Object. PutObjectResult result = client.putObject(bucketName, key, content, meta); // 打印ETag System.out.println(result.getETag()); } 

Object经过InputStream的形式上传到OSS中。在上面的例子里咱们能够看出,每上传一个Object,都须要指定和Object关联的ObjectMetadata。ObjectMetaData是用户对该object的描述,由一系列name-value对组成;其中ContentLength是必须设置的,以便SDK能够正确识别上传Object的大小。

Put Object请求处理成功后,OSS会将收到文件的MD5值放在返回结果的ETag中。用户能够根据ETag检验上传的文件与本地的是否一致。

关于Object的命名规范,参见 Object命名规范 。

关于上传Object更详细的信息,参见 上传Object 。

Step 4. 列出全部Object

当你完成一系列上传后,可能会须要查看在某个Bucket中有哪些Object,能够经过下面的程序实现:

public void listObjects(String bucketName) { // 初始化OSSClient OSSClient client = ...; // 获取指定bucket下的全部Object信息 ObjectListing listing = client.listObjects(bucketName); // 遍历全部Object for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) { System.out.println(objectSummary.getKey()); } } 

listObjects方法会返回ObjectListing对象,ObjectListing对象包含了这次listObject请求的返回结果。其中咱们能够经过ObjetListing中的getObjectSummaries方法获取全部Object的描述信息(List<OSSObjectSummary>)。

Step 5. 获取指定Object

你能够参考下面的代码简单地实现一个Object的获取:

public void getObject(String bucketName, String key) throws IOException { // 初始化OSSClient OSSClient client = ...; // 获取Object,返回结果为OSSObject对象 OSSObject object = client.getObject(bucketName, key); // 获取Object的输入流 InputStream objectContent = object.getObjectContent(); // 处理Object ... // 关闭流 objectContent.close(); } 

当调用OSSClient的getObject方法时,会返回一个OSSObject的对象,此对象包含了Object的各类信息。经过OSSObject的getObjectContent方法,还能够获取返回的Object的输入流,你能够读取这个输入流来对Object的内容进行操做;记得在用完以后关闭这个流。

 

OSSClient

OSSClient是OSS服务的Java客户端,它为调用者提供了一系列的方法,用于和OSS服务进行交互。

新建OSSClient

新建一个OSSClient很简单,以下面代码所示:

String key = "<key>"; String secret = "<secret>"; OSSClient client = new OSSClient(key, secret); 

上面的方式使用默认域名做为OSS的服务地址,若是你想本身指定域名,能够传入endpoint参数来指定。

String key = "<key>"; String secret = "<secret>"; String endpoint = "http://oss.aliyuncs.com"; OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret); 

配置OSSClient

若是你想配置OSSClient的一些细节的参数,能够在构造OSSClient的时候传入ClientConfiguration对象。 ClientConfiguration是OSS服务的配置类,能够为客户端配置代理,最大链接数等参数。

使用代理

下面一段代码可使客户端使用代理访问OSS服务:

// 建立ClientConfiguration实例
ClientConfiguration conf = new ClientConfiguration(); // 配置代理为本地8080端口 conf.setProxyHost("127.0.0.1"); conf.setProxyPort(8080); // 建立OSS客户端 client = new OSSClient(endpoint, accessKeySecret, accessKeySecret, conf); 

上面代码使得客户端的全部操做都会使用127.0.0.1地址的8080端口作代理执行。

对于有用户验证的代理,能够配置用户名和密码:

// 建立ClientConfiguration实例
ClientConfiguration conf = new ClientConfiguration(); // 配置代理为本地8080端口 conf.setProxyHost("127.0.0.1"); conf.setProxyPort(8080); //设置用户名和密码 conf.setProxyUsername("username"); conf.setProxyPassword("password"); 

设置网络参数

咱们能够用ClientConfiguration设置一些网络参数:

ClientConfiguration conf = new ClientConfiguration(); // 设置HTTP最大链接数为10 conf.setMaxConnections(10); // 设置TCP链接超时为5000毫秒 conf.setConnectionTimeout(5000); // 设置最大的重试次数为3 conf.setMaxErrorRetry(3); // 设置Socket传输数据超时的时间为2000毫秒 conf.setSocketTimeout(2000); 

ClientConfiguration全部参数

经过ClientConfiguration能指定的全部参数以下表所示:

参数 说明
UserAgent 用户代理,指HTTP的User-Agent头。默认为”aliyun-sdk-java”
ProxyHost 代理服务器主机地址
ProxyPort 代理服务器端口
ProxyUsername 代理服务器验证的用户名
ProxyPassword 代理服务器验证的密码
ProxyDomain 访问NTLM验证的代理服务器的Windows域名
ProxyWorkstation NTLM代理服务器的Windows工做站名称
MaxConnections 容许打开的最大HTTP链接数。默认为50
SocketTimeout 经过打开的链接传输数据的超时时间(单位:毫秒)。默认为50000毫秒
ConnectionTimeout 创建链接的超时时间(单位:毫秒)。默认为50000毫秒
MaxErrorRetry 可重试的请求失败后最大的重试次数。默认为3次

 

Bucket

Bucket是OSS上的命名空间,也是计费、权限控制、日志记录等高级功能的管理实体;Bucket名称在整个OSS服务中具备全局惟一性,且不能修改;存储在OSS上的每一个Object必须都包含在某个Bucket中。一个应用,例如图片分享网站,能够对应一个或多个Bucket。一个用户最多可建立10个Bucket,但每一个Bucket中存放的Object的数量和大小总和没有限制,用户不须要考虑数据的可扩展性。

命名规范

Bucket的命名有如下规范:

  • 只能包括小写字母,数字,短横线(-)
  • 必须以小写字母或者数字开头
  • 长度必须在3-63字节之间

新建Bucket

以下代码能够新建一个Bucket:

String bucketName = "my-bucket-name"; // 初始化OSSClient OSSClient client = ...; // 新建一个Bucket client.createBucket(bucketName); 

因为Bucket的名字是全局惟一的,因此尽可能保证你的 bucketName 不与别人重复。

列出用户全部的Bucket

下面代码能够列出用户全部的Bucket:

// 获取用户的Bucket列表
List<Bucket> buckets = client.listBuckets(); // 遍历Bucket for (Bucket bucket : buckets) { System.out.println(bucket.getName()); } 

判断Bucket是否存在

有时候,咱们的需求只是判断Bucket是否存在。则下面代码能够作到:

String bucketName = "your-bucket-name"; // 获取Bucket的存在信息 boolean exists = client.doesBucketExist(bucketName); // 输出结果 if (exists) { System.out.println("Bucket exists"); } else { System.out.println("Bucket not exists"); } 

删除Bucket

下面代码删除了一个Bucket:

String bucketName = "your-bucket-name"; // 删除Bucket client.deleteBucket(bucketName) 

须要注意的是,若是Bucket不为空(Bucket中有Object),则Bucket没法删除,必须清空Bucket后才能成功删除。

Bucket权限控制

Bucket的访问权限

OSS提供Bucket级别的权限访问控制,Bucket目前有三种访问权限:public-read-write,public-read和private。它们的含义以下:

  • public-read-write: 任何人(包括匿名访问)均可以对该bucket中的object进行上传、下载和删除操做;全部这些操做产生的费用由该bucket的建立者承担,请慎用该权限。
  • public-read: 只有该bucket的建立者能够对该bucket内的Object进行写操做(包括上传和删除);任何人(包括匿名访问)能够对该bucket中的object进行读操做。
  • private: 只有该bucket的建立者才能够访问此Bukcet。其余人禁止对此Bucket作任何操做。

用户新建立一个新Bucket时,若是不指定Bucket权限,OSS会自动为该Bucket设置private权限。对于一个已经存在的Bucket,只有它的建立者能够经过OSS的所提供的接口修改其访问权限。

修改Bucket的访问权限

下面代码将Bucket的权限设置为了private。

String bucketName = "your-bucket-name"; client.setBucketAcl(bucketName, CannedAccessControlList.Private); 

CannedAccessControlList是枚举类型,包含三个值: Private 、 PublicRead 、 PublicReadWrite ,它们分别对应相关权限。

 

Object

在OSS中,用户操做的基本数据单元是Object。单个Object最大容许存储5TB的数据。Object包含key、meta和data。其中,key是Object的名字;meta是用户对该object的描述,由一系列name-value对组成;data是Object的数据。

命名规范

Object的命名规范以下:

  • 使用UTF-8编码
  • 长度必须在1-1023字节之间
  • 不能以“/”或者“\”字符开头
  • 不能含有“\r”或者“\n”的换行符

上传Object

最简单的上传

以下代码:

public void putObject(String bucketName, String key, String filePath) throws FileNotFoundException { // 初始化OSSClient OSSClient client = ...; // 获取指定文件的输入流 File file = new File(filePath); InputStream content = new FileInputStream(file); // 建立上传Object的Metadata ObjectMetadata meta = new ObjectMetadata(); // 必须设置ContentLength meta.setContentLength(file.length()); // 上传Object. PutObjectResult result = client.putObject(bucketName, key, content, meta); // 打印ETag System.out.println(result.getETag()); } 

Object经过InputStream的形式上传到OSS中。在上面的例子里咱们能够看出,每上传一个Object,都须要指定和Object关联的ObjectMetadata。ObjectMetaData是用户对该object的描述,由一系列name-value对组成;其中ContentLength是必须设置的,以便SDK能够正确识别上传Object的大小。

Put Object请求处理成功后,OSS会将收到文件的MD5值放在返回结果的ETag中。用户能够根据ETag检验上传的文件与本地的是否一致。

设定Object的Http Header

OSS Java SDK本质上是调用后台的HTTP接口,所以OSS服务容许用户自定义Object的Http Header。下面代码为Object设置了过时时间:

// 初始化OSSClient
OSSClient client = ...; // 初始化上传输入流 InputStream content = ...; // 建立上传Object的Metadata ObjectMetadata meta = new ObjectMetadata(); // 设置ContentLength为1000 meta.setContentLength(1000); // 设置1小时后过时 Date expire = new Date(new Date().getTime() + 3600 * 1000); meta.setExpirationTime(expire); client.putObject(bucketName, key, content, meta); 

Java SDK支持的Http Header有四种,分别为:Cache-Control 、 Content-Disposition 、Content-Encoding 、 Expires 。它们的相关介绍见 RFC2616 。

用户自定义元数据

OSS支持用户自定义元数据来对Object进行描述。好比:

// 设置自定义元数据name的值为my-data
meta.addUserMetadata("name", "my-data"); // 上传object client.putObject(bucketName, key, content, meta); 

在上面代码中,用户自定义了一个名字为”name”,值为”my-data”的元数据。当用户下载此Object的时候,此元数据也能够一并获得。一个Object能够有多个相似的参数,但全部的user meta总大小不能超过2k。

分块上传

OSS容许用户将一个Object分红多个请求上传到后台服务器中,关于分块上传的内容,咱们将在 Object的分块上传 这一章中作介绍。

列出Bucket中的Object

列出Object

public void listObjects(String bucketName) { // 初始化OSSClient OSSClient client = ...; // 获取指定bucket下的全部Object信息 ObjectListing listing = client.listObjects(bucketName); // 遍历全部Object for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) { System.out.println(objectSummary.getKey()); } } 

listObjects方法会返回 ObjectListing 对象,ObjectListing 对象包含了这次listObject请求的返回结果。其中咱们能够经过 ObjetListing 中的 getObjectSummaries 方法获取全部Object的描述信息(List<OSSObjectSummary>)。

Note

 

默认状况下,若是Bucket中的Object数量大于100,则只会返回100个Object, 且返回结果中 IsTruncated 为 false,并返回 NextMarker 做为下此读取的起点。若想增大返回Object数目,能够修改 MaxKeys 参数,或者使用 Marker 参数分次读取。

扩展参数

一般,咱们能够经过设置ListObjectsRequest的参数来完成更强大的功能。好比:

// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName); // 设置参数 listObjectsRequest.setDelimiter("/"); listObjectsRequest.setMarker("123"); ... ObjectListing listing = client.listObjects(listObjectsRequest); 

上面代码中咱们调用了 listObjects 的一个重载方法,经过传入 ListObjectsRequest 来完成请求。经过 ListObjectsRequest 中的参数设置咱们能够完成不少扩展的功能。下表列出了 ListObjectsRequest 中能够设置的参数名称和做用:

名称 做用
Delimiter 是一个用于对Object名字进行分组的字符。全部名字包含指定的前缀且第一次出现Delimiter字符之间的object做为一组元素: CommonPrefixes。
Marker 设定结果从Marker以后按字母排序的第一个开始返回。
MaxKeys 限定这次返回object的最大数,若是不设定,默认为100,MaxKeys取值不能大于1000。
Prefix 限定返回的object key必须以Prefix做为前缀。注意使用prefix查询时,返回的key中仍会包含Prefix。

文件夹功能模拟

咱们能够经过 Delimiter 和 Prefix 参数的配合模拟出文件夹功能。

Delimiter 和 Prefix 的组合效果是这样的:若是把 Prefix 设为某个文件夹名,就能够罗列以此 Prefix 开头的文件,即该文件夹下递归的全部的文件和子文件夹。若是再把 Delimiter 设置为 “/” 时,返回值就只罗列该文件夹下的文件,该文件夹下的子文件名返回在 CommonPrefixes 部分,子文件夹下递归的文件和文件夹不被显示.

假设Bucket中有4个文件: oss.jpg , fun/test.jpg , fun/movie/001.avi , fun/movie/007.avi ,咱们把 “/” 符号做为文件夹的分隔符。

列出Bucket内全部文件

当咱们须要获取Bucket下的全部文件时,能够这样写:

// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName); // List Objects ObjectListing listing = client.listObjects(listObjectsRequest); // 遍历全部Object System.out.println("Objects:"); for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) { System.out.println(objectSummary.getKey()); } // 遍历全部CommonPrefix System.out.println("CommonPrefixs:"); for (String commonPrefix : listing.getCommonPrefixes()) { System.out.println(commonPrefix); } 

输出:

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

CommonPrefixs:

递归列出目录下全部文件

咱们能够经过设置 Prefix 参数来获取某个目录下全部的文件:

// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName); // 递归列出fun目录下的全部文件 listObjectsRequest.setPrefix("fun/"); ObjectListing listing = client.listObjects(listObjectsRequest); // 遍历全部Object System.out.println("Objects:"); for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) { System.out.println(objectSummary.getKey()); } // 遍历全部CommonPrefix System.out.println("\nCommonPrefixs:"); for (String commonPrefix : listing.getCommonPrefixes()) { System.out.println(commonPrefix); } 

输出:

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

CommonPrefixs:

列出目录下的文件和子目录

在 Prefix 和 Delimiter 结合的状况下,能够列出目录下的文件和子目录:

// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName); // "/" 为文件夹的分隔符 listObjectsRequest.setDelimiter("/"); // 列出fun目录下的全部文件和文件夹 listObjectsRequest.setPrefix("fun/"); ObjectListing listing = client.listObjects(listObjectsRequest); // 遍历全部Object System.out.println("Objects:"); for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) { System.out.println(objectSummary.getKey()); } // 遍历全部CommonPrefix System.out.println("\nCommonPrefixs:"); for (String commonPrefix : listing.getCommonPrefixes()) { System.out.println(commonPrefix); } 

输出:

Objects:
fun/test.jpg

CommonPrefixs:
fun/movie/

返回的结果中, ObjectSummaries 的列表中给出的是fun目录下的文件。而 CommonPrefixs 的列表中给出的是fun目录下的全部子文件夹。能够看出 fun/movie/001.avi , fun/movie/007.avi 两个文件并无被列出来,由于它们属于 fun 文件夹下的 movie 目录。

获取Object

简单的读取Object

咱们能够经过如下代码将Object读取到一个流中:

public void getObject(String bucketName, String key) throws IOException { // 初始化OSSClient OSSClient client = ...; // 获取Object,返回结果为OSSObject对象 OSSObject object = client.getObject(bucketName, key); // 获取ObjectMeta ObjectMetadata meta = object.getObjectMetadata(); // 获取Object的输入流 InputStream objectContent = object.getObjectContent(); // 处理Object ... // 关闭流 objectContent.close(); } 

`OSSObject 包含了Object的各类信息,包含Object所在的Bucket、Object的名称、Metadata以及一个输入流。咱们能够经过操做输入流将Object的内容读取到文件或者内存中。而ObjectMetadata包含了Object上传时定义的,ETag,Http Header以及自定义的元数据。

经过GetObjectRequest获取Object

为了实现更多的功能,咱们能够经过使用 GetObjectRequest 来获取Object。

// 初始化OSSClient
OSSClient client = ...; // 新建GetObjectRequest GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key); // 获取0~100字节范围内的数据 getObjectRequest.setRange(0, 100); // 获取Object,返回结果为OSSObject对象 OSSObject object = client.getObject(getObjectRequest); 

咱们经过 getObjectRequest 的 setRange 方法设置了返回的Object的范围。咱们能够用此功能实现文件的分段下载和断点续传。

GetObjectRequest能够设置如下参数:

参数 说明
Range 指定文件传输的范围。
ModifiedSinceConstraint 若是指定的时间早于实际修改时间,则正常传送文件。不然抛出304 Not Modified异常。
UnmodifiedSinceConstraint 若是传入参数中的时间等于或者晚于文件实际修改时间,则正常传输文件。不然抛出412 precondition failed异常
MatchingETagConstraints 传入一组ETag,若是传入指望的ETag和object的 ETag匹配,则正常传输文件。不然抛出412 precondition failed异常
NonmatchingEtagConstraints 传入一组ETag,若是传入的ETag值和Object的ETag不匹配,则正常传输文件。不然抛出304 Not Modified异常。
ResponseHeaderOverrides 自定义OSS返回请求中的一些Header。

修改 ResponseHeaderOverrides , 它提供了一系列的可修改参数,能够自定义OSS的返回Header,以下表所示:

参数 说明
ContentType OSS返回请求的content-type头
ContentLanguage OSS返回请求的content-language头
Expires OSS返回请求的expires头
CacheControl OSS返回请求的cache-control头
ContentDisposition OSS返回请求的content-disposition头
ContentEncoding OSS返回请求的content-encoding头

直接下载Object到文件

咱们能够经过下面的代码直接将Object下载到指定文件:

// 新建GetObjectRequest
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key); // 下载Object到文件 ObjectMetadata objectMetadata = client.getObject(getObjectRequest, new File("/path/to/file")); 

当使用上面方法将Object直接下载到文件时,方法返回ObjectMetadata对象。

只获取ObjectMetadata

经过 getObjectMetadata 方法能够只获取ObjectMetadata而不获取Object的实体。以下代码所示:

ObjectMetadata objectMetadata = client.getObjectMetadata(bucketName, key); 

删除Object

下面代码删除了一个Object:

public void deleteObject(String bucketName, String key) { // 初始化OSSClient OSSClient client = ...; // 删除Object client.deleteObject(bucketName, key); } 

拷贝Object

拷贝一个Object

经过 copyObject 方法咱们能够拷贝一个Object,以下面代码:

public void copyObject(String srcBucketName, String srcKey, String destBucketName, String destKey) { // 初始化OSSClient OSSClient client = ...; // 拷贝Object CopyObjectResult result = client.copyObject(srcBucketName, srcKey, destBucketName, destKey); // 打印结果 System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified()); } 

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

经过CopyObjectRequest拷贝Object

也能够经过 CopyObjectRequest 实现Object的拷贝:

// 初始化OSSClient
OSSClient client = ...; // 建立CopyObjectRequest对象 CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey); // 设置新的Metadata ObjectMetadata meta = new ObjectMetadata(); meta.setContentType("text/html"); copyObjectRequest.setNewObjectMetadata(meta); // 复制Object CopyObjectResult result = client.copyObject(copyObjectRequest); System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified()); 

CopyObjectRequest 容许用户修改目的Object的ObjectMeta,同时也提供 ModifiedSinceConstraint , UnmodifiedSinceConstraint , MatchingETagConstraints , NonmatchingEtagConstraints 四个参数的设定, 用法与 GetObjectRequest 的参数类似,参见 GetObjectRequest的可设置参数

 

Object的分块上传

除了经过putObject接口上传文件到OSS之外,OSS还提供了另一种上传模式 —— Multipart Upload。用户能够在以下的应用场景内(但不只限于此),使用Multipart Upload上传模式,如:

  • 须要支持断点上传。
  • 上传超过100MB大小的文件。
  • 网络条件较差,和OSS的服务器之间的连接常常断开。
  • 须要流式地上传文件。
  • 上传文件以前,没法肯定上传文件的大小。

下面咱们将一步步介绍怎样实现Multipart Upload。

分步完成Multipart Upload

假设咱们有一个文件,本地路径为 /path/to/file.zip 因为文件比较大,咱们将其分块传输到OSS中。

1. 初始化Multipart Upload

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

String bucketName = "your-bucket-name"; String key = "your-key"; // 初始化OSSClient OSSClient client = ...; // 开始Multipart Upload InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketName, key); InitiateMultipartUploadResult initiateMultipartUploadResult = client.initiateMultipartUpload(initiateMultipartUploadRequest); // 打印UploadId System.out.println("UploadId: " + initiateMultipartUploadResult.getUploadId()); 

咱们用 InitiateMultipartUploadRequest 来指定上传Object的名字和所属Bucket。在 InitiateMultipartUploadRequest 中,你也能够设置 ObjectMetadata ,可是没必要指定其中的 ContentLength (指定了也无效)。

initiateMultipartUpload 的返回结果中含有 UploadId ,它是区分分块上传事件的惟一标识,在后面的操做中,咱们将用到它。

2. 上传分块

接着,咱们把文件分块上传。

// 设置每块为 5M
final int partSize = 1024 * 1024 * 5; 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>(); for(int i = 0; i < partCount; i++){ // 获取文件流 FileInputStream fis = new FileInputStream(partFile); // 跳到每一个分块的开头 long skipBytes = partSize * i; fis.skip(skipBytes); // 计算每一个分块的大小 long size = partSize < partFile.length() - skipBytes ? partSize : partFile.length() - skipBytes; // 建立UploadPartRequest,上传分块 UploadPartRequest uploadPartRequest = new UploadPartRequest(); uploadPartRequest.setBucketName(bucketName); uploadPartRequest.setKey(key); uploadPartRequest.setUploadId(initiateMultipartUploadResult.getUploadId()); uploadPartRequest.setInputStream(fis); uploadPartRequest.setPartSize(size); uploadPartRequest.setPartNumber(i + 1); UploadPartResult uploadPartResult = client.uploadPart(uploadPartRequest); // 将返回的PartETag保存到List中。 partETags.add(uploadPartResult.getPartETag()); // 关闭文件 fis.close(); } 

上面程序的核心是调用 uploadPart 方法来上传每个分块,可是要注意如下几点:

  • uploadPart 方法要求除最后一个Part之外,其余的Part大小都要大于5MB。可是Upload Part接口并不会当即校验上传Part的大小(由于不知道是否为最后一块);只有当Complete Multipart Upload的时候才会校验。
  • OSS会将服务器端收到Part数据的MD5值放在ETag头内返回给用户。为了保证数据在网络传输过程当中不出现错误,强烈推荐用户在收到OSS的返回请求后,用该MD5值验证上传数据的正确性。
  • Part号码的范围是1~10000。若是超出这个范围,OSS将返回InvalidArgument的错误码。
  • 每次上传part时都要把流定位到这次上传块开头所对应的位置。
  • 每次上传part以后,OSS的返回结果会包含一个 PartETag 对象,他是上传块的ETag与块编号(PartNumber)的组合,在后续完成分块上传的步骤中会用到它,所以咱们须要将其保存起来。通常来说咱们将这些 PartETag 对象保存到List中。

3. 完成分块上传

完成分块上传很简单,以下:

CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, key, initiateMultipartUploadResult.getUploadId(), partETags); // 完成分块上传 CompleteMultipartUploadResult completeMultipartUploadResult = client.completeMultipartUpload(completeMultipartUploadRequest); // 打印Object的ETag System.out.println(completeMultipartUploadResult.getETag()); 

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

completeMultipartUpload 方法的返回结果中会包含拼装后Object的ETag,用户能够和本地文件的MD5值进行校验以保证数据的有效性。

取消分块上传事件

咱们能够用 abortMultipartUpload 方法取消分块上传。

AbortMultipartUploadRequest abortMultipartUploadRequest = new AbortMultipartUploadRequest(bucketName, key, uploadId); // 取消分块上传 client.abortMultipartUpload(abortMultipartUploadRequest); 

获取Bucket内全部分块上传事件

咱们能够用 listMultipartUploads 方法获取Bucket内全部上传事件。

// 获取Bucket内全部上传事件
MultipartUploadListing listing = client.listMultipartUploads(listMultipartUploadsRequest); // 遍历全部上传事件 for (MultipartUpload multipartUpload : listing.getMultipartUploads()) { System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId()); } 

Note

 

默认状况下,若是Bucket中的分块上传事件的数量大于1000,则只会返回1000个Object, 且返回结果中 IsTruncated 为 false,并返回 NextKeyMarker 和 NextUploadMarker 做为下此读取的起点。若想增大返回分块上传事件数目,能够修改 MaxUploads 参数,或者使用 KeyMarker 以及 UploadIdMarker 参数分次读取。

获取全部已上传的块信息

咱们能够用 listParts 方法获取某个上传事件全部已上传的块。

ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, uploadId); // 获取上传的全部Part信息 PartListing partListing = client.listParts(listPartsRequest); // 遍历全部Part for (PartSummary part : partListing.getParts()) { System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag()); } 

Note

 

默认状况下,若是Bucket中的分块上传事件的数量大于1000,则只会返回1000个Object, 且返回结果中 IsTruncated 为 false,并返回 NextPartNumberMarker 做为下此读取的起点。若想增大返回分块上传事件数目,能够修改 MaxParts 参数,或者使用 PartNumberMarker 参数分次读取。

 

生成预签名URL

若是你想把本身的资源发放给第三方用户访问,可是又不想开放Bucket的读权限,能够经过生成预签名URL的形式提供给用户一个临时的访问URL。在生成URL时,你能够指定URL过时的时间,从而限制用户长时间访问。

生成一个预签名的URL

以下代码:

String bucketName = "your-bucket-name"; String key = "your-object-key"; // 设置URL过时时间为1小时 Date expiration = new Date(new Date().getTime() + 3600 * 1000); // 生成URL URL url = client.generatePresignedUrl(bucketName, key, expiration); 

生成的URL默认以GET方式访问,这样,用户能够直接经过浏览器访问相关内容。

生成其余Http方法的URL

若是你想容许用户临时进行其余操做(好比上传,删除Object),可能须要签名其余方法的URL,以下:

// 生成PUT方法的URL
URL url = client.generatePresignedUrl(bucketName, key, expiration, HttpMethod.PUT); 

经过传入 HttpMethod.PUT 参数,用户可使用生成的URL上传Object。

添加用户自定义参数(UserMetadata)

若是你想使用签名的URL上传Object,并指定UserMetadata等参数,能够这样作:

// 建立请求
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key); // HttpMethod为PUT generatePresignedUrlRequest.setMethod(HttpMethod.PUT); // 添加UserMetadata generatePresignedUrlRequest.addUserMetadata("key", "value"); // 生成预签名的URL URL url = client.generatePresignedUrl(bucketName, key, expiration); 

须要注意的是,上述过程只是生成了签名的URL,你仍须要在request header中添加UserMetadata的信息。

关于如何在Http请求中设置UserMetadata等参数,能够参考 OSS REST API 文档 中的相关内容。

 

异常

OSS Java SDK 中有两种异常 ClientException 以及 OSSException , 他们都继承自或者间接继承自 RuntimeException 。

ClientException

ClientException指SDK内部出现的异常,好比未设置BucketName,网络没法到达等等。

OSSException

OSSException指服务器端错误,它来自于对服务器错误信息的解析。OSSException通常有如下几个成员:

  • Code: OSS返回给用户的错误码。
  • Message: OSS给出的详细错误信息。
  • RequestId: 用于惟一标识该次请求的UUID;当你没法解决问题时,能够凭这个RequestId来请求OSS开发工程师的帮助。
  • HostId: 用于标识访问的OSS集群(目前统一为oss.aliyuncs.com)

下面是OSS中常见的异常:

错误码 描述
AccessDenied 拒绝访问
BucketAlreadyExists Bucket已经存在
BucketNotEmpty Bucket不为空
EntityTooLarge 实体过大
EntityTooSmall 实体太小
FileGroupTooLarge 文件组过大
FilePartNotExist 文件Part不存在
FilePartStale 文件Part过期
InvalidArgument 参数格式错误
InvalidAccessKeyId Access Key ID不存在
InvalidBucketName 无效的Bucket名字
InvalidDigest 无效的摘要
InvalidObjectName 无效的Object名字
InvalidPart 无效的Part
InvalidPartOrder 无效的part顺序
InvalidTargetBucketForLogging Logging操做中有无效的目标bucket
InternalError OSS内部发生错误
MalformedXML XML格式非法
MethodNotAllowed 不支持的方法
MissingArgument 缺乏参数
MissingContentLength 缺乏内容长度
NoSuchBucket Bucket不存在
NoSuchKey 文件不存在
NoSuchUpload Multipart Upload ID不存在
NotImplemented 没法处理的方法
PreconditionFailed 预处理错误
RequestTimeTooSkewed 发起请求的时间和服务器时间超出15分钟
RequestTimeout 请求超时
SignatureDoesNotMatch 签名错误
TooManyBuckets 用户的Bucket数目超过限制

 

 

         做者:王超    原文:http://aliyun_portal_storage.oss.aliyuncs.com/oss_api/oss_javahtml/index.html

相关文章
相关标签/搜索