全部產品
Search
文件中心

Object Storage Service:分區上傳

更新時間:Jan 12, 2024

分區上傳(Multipart Upload)分為以下三個步驟:

  1. 初始化一個分區上傳事件。 調用ossClient.initiateMultipartUpload方法返回OSS建立的全域唯一的uploadId。

  2. 上傳分區。 調用ossClient.uploadPart方法上傳分區資料。需要注意:

    • 對於同一個uploadId,分區號(partNumber)標識了該分區在整個檔案內的相對位置。如果使用同一個分區號上傳了新的資料,那麼OSS上這個分區已有的資料將會被覆蓋。
    • OSS將收到的分區資料的MD5值放在ETag頭內返回給使用者。
    • SDK自動化佈建Content-MD5。OSS計算上傳資料的MD5值,並與SDK計算的MD5值比較,如果不一致則返回InvalidDigest錯誤碼。
  3. 完成分區上傳。 所有分區上傳完成後,調用ossClient.completeMultipartUpload方法將所有分區合并成完整的檔案。

以下通過一個完整的樣本對分區上傳的流程進行逐步解析:

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

/* 步驟1:初始化一個分區上傳事件。
*/
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
InitiateMultipartUploadResult result = ossClient.initiateMultipartUpload(request);
// 返回uploadId,它是分區上傳事件的唯一標識,您可以根據這個ID來發起相關的操作,如取消分區上傳、查詢分區上傳等。
String uploadId = result.getUploadId();

/* 步驟2:上傳分區。
*/
// partETags是PartETag的集合。PartETag由分區的ETag和分區號組成。
List<PartETag> partETags =  new ArrayList<PartETag>();
// 計算檔案有多少個分區。
final long partSize = 1 * 1024 * 1024L;   // 1MB
final File sampleFile = new File("<localFile>");
long fileLength = sampleFile.length();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
    partCount++;
 }
// 遍曆分區上傳。
for (int i = 0; i < partCount; i++) {
    long startPos = i * partSize;
    long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
    InputStream instream = new FileInputStream(sampleFile);
    // 跳過已經上傳的分區。
    instream.skip(startPos);
    UploadPartRequest uploadPartRequest = new UploadPartRequest();
    uploadPartRequest.setBucketName(bucketName);
    uploadPartRequest.setKey(objectName);
    uploadPartRequest.setUploadId(uploadId);
    uploadPartRequest.setInputStream(instream);
    // 設定分區大小。除了最後一個分區沒有大小限制,其他的分區最小為100KB。
    uploadPartRequest.setPartSize(curPartSize);
    // 設定分區號。每一個上傳的分區都有一個分區號,取值範圍是1~10000,如果超出這個範圍,OSS將返回InvalidArgument的錯誤碼。
    uploadPartRequest.setPartNumber( i + 1);
    // 每個分區不需要按順序上傳,甚至可以在不同用戶端上傳,OSS會按照分區號排序組成完整的檔案。
    UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
    // 每次上傳分區之後,OSS的返回結果會包含一個PartETag。PartETag將被保存到partETags中。
    partETags.add(uploadPartResult.getPartETag());
}

/* 步驟3:完成分區上傳。
*/
// 排序。partETags必須按分區號升序排列。
Collections.sort(partETags, new Comparator<PartETag>() {
    public int compare(PartETag p1, PartETag p2) {
        return p1.getPartNumber() - p2.getPartNumber();
    }
});
// 在執行該操作時,需要提供所有有效partETags。OSS收到提交的partETags後,會逐一驗證每個分區的有效性。當所有的資料分區驗證通過後,OSS將把這些分區組合成一個完整的檔案。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
ossClient.completeMultipartUpload(completeMultipartUploadRequest);

// 關閉OSSClient。
ossClient.shutdown();

分區上傳的完整代碼請參見GitHub

您可以調用ossClient.abortMultipartUpload方法來取消分區上傳事件。當一個分區上傳事件被取消後,無法再使用這個uploadId做任何操作,已經上傳的分區資料會被刪除。

以下代碼用於取消分區上傳事件:

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 取消分區上傳,其中uploadId來自於InitiateMultipartUpload。
AbortMultipartUploadRequest abortMultipartUploadRequest =
        new AbortMultipartUploadRequest("<yourBucketName>", "<yourObjectName>", "<uploadId>");
ossClient.abortMultipartUpload(abortMultipartUploadRequest);

// 關閉OSSClient。
ossClient.shutdown();

列舉已上傳的分區

調用ossClient.listParts方法列舉出指定uploadId下所有已經上傳成功的分區。

簡單列舉已上傳的分區

以下代碼用於簡單列舉已上傳的分區:

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 列舉已上傳的分區,其中uploadId來自於InitiateMultipartUpload返回的結果。
ListPartsRequest listPartsRequest = new ListPartsRequest("<yourBucketName>", "<yourObjectName>", "<uploadId>");
 // 設定uploadId。
 //listPartsRequest.setUploadId(uploadId);
 // 設定分頁時每一頁中分區數量為100個。預設列舉1000個分區。
 listPartsRequest.setMaxParts(100);
 // 指定List的起始位置。只有分區號大於該參數值的分區會被列出。
 listPartsRequest.setPartNumberMarker(2);
PartListing partListing = ossClient.listParts(listPartsRequest);

for (PartSummary part : partListing.getParts()) {
    // 獲取分區號。
    part.getPartNumber();
    // 獲取分區資料大小。
    part.getSize();
    // 獲取分區的ETag。
    part.getETag();
    // 獲取分區的最後修改時間。
    part.getLastModified();
}

// 關閉OSSClient。
ossClient.shutdown();

列舉所有已上傳的分區

預設情況下,listParts只能一次列舉1000個分區。當分區數量大於1000時,請使用以下代碼列舉所有已上傳的分區。

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 列舉所有已上傳的分區。
PartListing partListing;
ListPartsRequest listPartsRequest = new ListPartsRequest("<yourBucketName>", "<yourObjectName>", "<uploadId>");

do {
    partListing = ossClient.listParts(listPartsRequest);

    for (PartSummary part : partListing.getParts()) {
        // 獲取分區號。
        part.getPartNumber();
        // 獲取分區資料大小。
        part.getSize();
        // 獲取分區的ETag。
        part.getETag();
        // 獲取分區的最後修改時間。
        part.getLastModified();
    }
// 指定List的起始位置,只有分區號大於該參數值的分區會被列出。
listPartsRequest.setPartNumberMarker(partListing.getNextPartNumberMarker());
} while (partListing.isTruncated());

// 關閉OSSClient。
ossClient.shutdown()

分頁列舉所有已上傳的分區

以下代碼用於指定每頁分區的數量,分頁列舉所有分區。

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 分頁列舉已上傳的分區。
PartListing partListing;
ListPartsRequest listPartsRequest = new ListPartsRequest("<yourBucketName>", "<yourObjectName>", "<uploadId>");
// 設定分頁時每一頁100個分區。
listPartsRequest.setMaxParts(100);

do {
    partListing = ossClient.listParts(listPartsRequest);

    for (PartSummary part : partListing.getParts()) {
        // 獲取分區號。
        part.getPartNumber();
        // 獲取分區資料大小。
        part.getSize();
        // 獲取分區的ETag。
        part.getETag();
        // 獲取分區的最後修改時間。
        part.getLastModified();
    }

    listPartsRequest.setPartNumberMarker(partListing.getNextPartNumberMarker());

} while (partListing.isTruncated());

// 關閉OSSClient。
ossClient.shutdown();

列舉分區上傳事件

調用ossClient.listMultipartUploads方法列舉出所有執行中的分區上傳事件,即已初始化但尚未完成或已取消的分區上傳事件。可設定的參數如下:

參數 作用 如何設定
prefix 限定返回的檔案名稱必須以指定的prefix作為首碼。注意使用prefix查詢時,返回的檔案名稱中仍會包含prefix。 ListMultipartUploadsRequest.setPrefix(String prefix)
delimiter 用於對檔案名稱進行分組的一個字元。所有名稱包含指定的首碼且第一次出現delimiter字元之間的檔案作為一組元素。 ListMultipartUploadsRequest.setDelimiter(String delimiter)
maxUploads 限定此次返回分區上傳事件的最大數目,預設值和最大值均為1000。 ListMultipartUploadsRequest.setMaxUploads(Integer maxUploads)
keyMarker 所有檔案名稱的字母序大於keyMarker參數值的分區上傳事件。可以與uploadIdMarker參數一同使用來指定返回結果的起始位置。 ListMultipartUploadsRequest.setKeyMarker(String keyMarker)
uploadIdMarker 與keyMarker參數一同使用來指定返回結果的起始位置。 如果未設定keyMarker參數,則此參數無效。如果設定了keyMarker參數,則查詢結果中包含: - 名稱的字母序大於keyMarker參數值的所有檔案。 - 檔案名稱等於keyMarker參數值且uploadId比uploadIdMarker參數值大的所有分區上傳事件。 ListMultipartUploadsRequest.setUploadIdMarker(String uploadIdMarker)

簡單列舉分區上傳事件

以下代碼用於列舉分區上傳事件:

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 列舉分區上傳事件。預設列舉1000個分區。
ListMultipartUploadsRequest listMultipartUploadsRequest = new ListMultipartUploadsRequest(bucketName);
MultipartUploadListing multipartUploadListing = ossClient.listMultipartUploads(listMultipartUploadsRequest);

for (MultipartUpload multipartUpload : multipartUploadListing.getMultipartUploads()) {
    // 獲取uploadId。
    multipartUpload.getUploadId();
    // 獲取Key。
    multipartUpload.getKey();
    // 獲取分區上傳的初始化時間。
    multipartUpload.getInitiated();
}

// 關閉OSSClient。
ossClient.shutdown();

返回結果中isTruncated為false,返回nextKeyMarker和nextUploadIdMarker作為下次讀取的起點。如果沒有一次性獲取所有的上傳事件,可以採用分頁列舉的方式。

列舉全部分區上傳事件

預設情況下,listMultipartUploads 只能一次列舉1000個分區。當分區數量大於1000時,請使用以下代碼列舉全部分區上傳事件。

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 列舉分區上傳事件。
MultipartUploadListing multipartUploadListing;
ListMultipartUploadsRequest listMultipartUploadsRequest = new ListMultipartUploadsRequest(bucketName);

do {
    multipartUploadListing = ossClient.listMultipartUploads(listMultipartUploadsRequest);

    for (MultipartUpload multipartUpload : multipartUploadListing.getMultipartUploads()) {
        // 獲取uploadId。
        multipartUpload.getUploadId();
        // 獲取檔案名稱。
        multipartUpload.getKey();
        // 獲取分區上傳的初始化時間。
        multipartUpload.getInitiated();
    }

    listMultipartUploadsRequest.setKeyMarker(multipartUploadListing.getNextKeyMarker());

    listMultipartUploadsRequest.setUploadIdMarker(multipartUploadListing.getNextUploadIdMarker());
} while (multipartUploadListing.isTruncated());

// 關閉OSSClient。
ossClient.shutdown();

分頁列舉全部上傳事件

以下代碼用於分頁列舉所有上傳事件:

// Endpoint以杭州為例,其它Region請按實際情況填寫。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里雲主帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM帳號進行API訪問或日常運維,請登入 https://ram.console.aliyun.com 建立RAM帳號。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";

// 建立OSSClient執行個體。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

// 列舉分區上傳事件。
MultipartUploadListing multipartUploadListing;
ListMultipartUploadsRequest listMultipartUploadsRequest = new ListMultipartUploadsRequest(bucketName);
// 設定每頁列舉的分區上傳事件數目目。
listMultipartUploadsRequest.setMaxUploads(50);

do {
    multipartUploadListing = ossClient.listMultipartUploads(listMultipartUploadsRequest);

    for (MultipartUpload multipartUpload : multipartUploadListing.getMultipartUploads()) {
        // 獲取uploadId。
        multipartUpload.getUploadId();
        // 獲取Key。
        multipartUpload.getKey();
        // 獲取分區上傳的初始化時間。
        multipartUpload.getInitiated();
    }

    listMultipartUploadsRequest.setKeyMarker(multipartUploadListing.getNextKeyMarker());
    listMultipartUploadsRequest.setUploadIdMarker(multipartUploadListing.getNextUploadIdMarker());

} while (multipartUploadListing.isTruncated());

// 關閉OSSClient。
ossClient.shutdown();