步驟以下:php
通過上面幾步以後,你就能夠在工程中使用OSS JAVA SDK了。html
在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完成一些基本的操做。瀏覽器
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
Bucket是OSS上的命名空間,至關於數據的容器,能夠存儲若干數據實體(Object)。
你能夠按照下面的代碼新建一個Bucket:
public void createBucket(String bucketName) { // 初始化OSSClient OSSClient client = ...; // 新建一個Bucket client.createBucket(bucketName); }
因爲Bucket的名字是全局惟一的,因此儘可能保證你的 bucketName 不與別人重複。
關於Bucket的命名規範,參見 Bucket命名規範。
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 。
當你完成一系列上傳後,可能會須要查看在某個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>)。
你能夠參考下面的代碼簡單地實現一個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是OSS服務的Java客戶端,它爲調用者提供了一系列的方法,用於和OSS服務進行交互。
新建一個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的時候傳入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能指定的全部參數以下表所示:
參數 | 說明 |
---|---|
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是OSS上的命名空間,也是計費、權限控制、日誌記錄等高級功能的管理實體;Bucket名稱在整個OSS服務中具備全局惟一性,且不能修改;存儲在OSS上的每一個Object必須都包含在某個Bucket中。一個應用,例如圖片分享網站,能夠對應一個或多個Bucket。一個用戶最多可建立10個Bucket,但每一個Bucket中存放的Object的數量和大小總和沒有限制,用戶不須要考慮數據的可擴展性。
Bucket的命名有如下規範:
以下代碼能夠新建一個Bucket:
String bucketName = "my-bucket-name"; // 初始化OSSClient OSSClient client = ...; // 新建一個Bucket client.createBucket(bucketName);
因爲Bucket的名字是全局惟一的,因此儘可能保證你的 bucketName 不與別人重複。
下面代碼能夠列出用戶全部的Bucket:
// 獲取用戶的Bucket列表
List<Bucket> buckets = client.listBuckets(); // 遍歷Bucket for (Bucket bucket : buckets) { System.out.println(bucket.getName()); }
有時候,咱們的需求只是判斷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:
String bucketName = "your-bucket-name"; // 刪除Bucket client.deleteBucket(bucketName)
須要注意的是,若是Bucket不爲空(Bucket中有Object),則Bucket沒法刪除,必須清空Bucket後才能成功刪除。
OSS提供Bucket級別的權限訪問控制,Bucket目前有三種訪問權限:public-read-write,public-read和private。它們的含義以下:
用戶新建立一個新Bucket時,若是不指定Bucket權限,OSS會自動爲該Bucket設置private權限。對於一個已經存在的Bucket,只有它的建立者能夠經過OSS的所提供的接口修改其訪問權限。
下面代碼將Bucket的權限設置爲了private。
String bucketName = "your-bucket-name"; client.setBucketAcl(bucketName, CannedAccessControlList.Private);
CannedAccessControlList是枚舉類型,包含三個值: Private 、 PublicRead 、 PublicReadWrite ,它們分別對應相關權限。
在OSS中,用戶操做的基本數據單元是Object。單個Object最大容許存儲5TB的數據。Object包含key、meta和data。其中,key是Object的名字;meta是用戶對該object的描述,由一系列name-value對組成;data是Object的數據。
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檢驗上傳的文件與本地的是否一致。
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的分塊上傳 這一章中作介紹。
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下的全部文件時,能夠這樣寫:
// 構造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讀取到一個流中:
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。
// 初始化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下載到指定文件:
// 新建GetObjectRequest
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key); // 下載Object到文件 ObjectMetadata objectMetadata = client.getObject(getObjectRequest, new File("/path/to/file"));
當使用上面方法將Object直接下載到文件時,方法返回ObjectMetadata對象。
經過 getObjectMetadata 方法能夠只獲取ObjectMetadata而不獲取Object的實體。以下代碼所示:
ObjectMetadata objectMetadata = client.getObjectMetadata(bucketName, key);
下面代碼刪除了一個Object:
public void deleteObject(String bucketName, String key) { // 初始化OSSClient OSSClient client = ...; // 刪除Object client.deleteObject(bucketName, key); }
經過 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的拷貝:
// 初始化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的可設置參數。
除了經過putObject接口上傳文件到OSS之外,OSS還提供了另一種上傳模式 —— Multipart Upload。用戶能夠在以下的應用場景內(但不只限於此),使用Multipart Upload上傳模式,如:
下面咱們將一步步介紹怎樣實現Multipart Upload。
假設咱們有一個文件,本地路徑爲 /path/to/file.zip 因爲文件比較大,咱們將其分塊傳輸到OSS中。
咱們使用 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 ,它是區分分塊上傳事件的惟一標識,在後面的操做中,咱們將用到它。
接着,咱們把文件分塊上傳。
// 設置每塊爲 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 方法來上傳每個分塊,可是要注意如下幾點:
完成分塊上傳很簡單,以下:
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);
咱們能夠用 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 參數分次讀取。
若是你想把本身的資源發放給第三方用戶訪問,可是又不想開放Bucket的讀權限,能夠經過生成預簽名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方式訪問,這樣,用戶能夠直接經過瀏覽器訪問相關內容。
若是你想容許用戶臨時進行其餘操做(好比上傳,刪除Object),可能須要簽名其餘方法的URL,以下:
// 生成PUT方法的URL
URL url = client.generatePresignedUrl(bucketName, key, expiration, HttpMethod.PUT);
經過傳入 HttpMethod.PUT 參數,用戶可使用生成的URL上傳Object。
若是你想使用簽名的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指SDK內部出現的異常,好比未設置BucketName,網絡沒法到達等等。
OSSException指服務器端錯誤,它來自於對服務器錯誤信息的解析。OSSException通常有如下幾個成員:
下面是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