OSS JAVA SDK


安裝OSS JAVA SDK

直接在Eclipse中使用JAR包

步驟如下:

  • 在官方網站下載 Open Service Java SDK 。
  • 解壓文件。
  • 將解壓后文件夾中的文件: aliyun-openservice-<versionId>.jar 以及lib文件夾下的所有文件拷貝到你的工程文件夾中。
  • 在Eclipse右鍵工程 -> Properties -> Java Build Path -> Add JARs 。
  • 選擇你拷貝的所有JAR文件。

經過上面幾步之后,你就可以在工程中使用OSS JAVA SDK了。

在Maven工程中使用SDK

在Maven工程中使用JAVA SDK十分簡單,只要在在pom.xml文件中加入依賴就可以了。

在 dependencies 標簽內加入如下內容:

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

version為版本號,隨着版本更新可能有變動。

 

快速入門

在這一章里,您將學到如何用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做簽名驗證。

關於OSSClient的詳細介紹,參見 OSSClient 。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM