全部產品
Search
文件中心

Object Storage Service:上傳檔案

更新時間:Aug 30, 2018

OSS 移動端SDK 上傳檔案的方式可以分為:簡單上傳,追加上傳,分區上傳和斷點續傳。

簡單上傳

上傳Object可以直接上傳OSSData,或者通過NSURL上傳一個檔案:

  1. OSSPutObjectRequest * put = [OSSPutObjectRequest new];
  2. // 必要欄位
  3. put.bucketName = @"<bucketName>";
  4. put.objectKey = @"<objectKey>";
  5. put.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
  6. // put.uploadingData = <NSData *>; // 直接上傳NSData
  7. // 可選欄位,可不設定
  8. put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
  9. // 當前上傳段長度、當前已經上傳總長度、一共需要上傳的總長度
  10. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
  11. };
  12. // 以下可選欄位的含義參考: https://docs.aliyun.com/#/pub/oss/api-reference/object&PutObject
  13. // put.contentType = @"";
  14. // put.contentMd5 = @"";
  15. // put.contentEncoding = @"";
  16. // put.contentDisposition = @"";
  17. // put.objectMeta = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"value1", @"x-oss-meta-name1", nil]; // 可以在上傳時設定元資訊或者其他HTTP頭部
  18. OSSTask * putTask = [client putObject:put];
  19. [putTask continueWithBlock:^id(OSSTask *task) {
  20. if (!task.error) {
  21. NSLog(@"upload object success!");
  22. } else {
  23. NSLog(@"upload object failed, error: %@" , task.error);
  24. }
  25. return nil;
  26. }];
  27. // [putTask waitUntilFinished];
  28. // [put cancel];

上傳到檔案目錄

OSS服務是沒有檔案夾這個概念的,所有元素都是以檔案來儲存,但給使用者提供了建立模擬檔案夾的方式。建立模擬檔案夾本質上來說是建立了一個名字以“/”結尾的檔案,對於這個檔案照樣可以上傳下載,只是控制台會對以“/”結尾的檔案以檔案夾的方式展示。

如,在上傳檔案是,如果把ObjectKey寫為"folder/subfolder/file",即是模擬了把檔案上傳到folder/subfolder/下的file檔案。注意,路徑預設是”根目錄”,不需要以’/‘開頭。

上傳時設定Content-Type和開啟校驗MD5

上傳時可以顯式指定ContentType,如果沒有指定,SDK會根據檔案名或者上傳的ObjectKey自動判斷。另外,上傳Object時如果設定了Content-Md5,那麼OSS會用之檢查消息內容是否與發送時一致。SDK提供了方便的Base64和MD5計算方法。

  1. OSSPutObjectRequest * put = [OSSPutObjectRequest new];
  2. // 必要欄位
  3. put.bucketName = @"<bucketName>";
  4. put.objectKey = @"<objectKey>";
  5. put.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
  6. // put.uploadingData = <NSData *>; // 直接上傳NSData
  7. // 設定Content-Type,可選
  8. put.contentType = @"application/octet-stream";
  9. // 設定MD5校驗,可選
  10. put.contentMd5 = [OSSUtil base64Md5ForFilePath:@"<filePath>"]; // 如果是檔案路徑
  11. // put.contentMd5 = [OSSUtil base64Md5ForData:<NSData *>]; // 如果是位元據
  12. // 進度設定,可選
  13. put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
  14. // 當前上傳段長度、當前已經上傳總長度、一共需要上傳的總長度
  15. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
  16. };
  17. OSSTask * putTask = [client putObject:put];
  18. [putTask continueWithBlock:^id(OSSTask *task) {
  19. if (!task.error) {
  20. NSLog(@"upload object success!");
  21. } else {
  22. NSLog(@"upload object failed, error: %@" , task.error);
  23. }
  24. return nil;
  25. }];
  26. // [putTask waitUntilFinished];
  27. // [put cancel];

追加上傳

Append Object以追加寫的方式上傳檔案。通過Append Object操作建立的Object類型為Appendable Object,而通過Put Object上傳的Object是Normal Object。

  1. OSSAppendObjectRequest * append = [OSSAppendObjectRequest new];
  2. // 必要欄位
  3. append.bucketName = @"<bucketName>";
  4. append.objectKey = @"<objectKey>";
  5. append.appendPosition = 0; // 指定從何處進行追加
  6. NSString * docDir = [self getDocumentDirectory];
  7. append.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
  8. // 可選欄位
  9. append.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
  10. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
  11. };
  12. // 以下可選欄位的含義參考:https://docs.aliyun.com/#/pub/oss/api-reference/object&AppendObject
  13. // append.contentType = @"";
  14. // append.contentMd5 = @"";
  15. // append.contentEncoding = @"";
  16. // append.contentDisposition = @"";
  17. OSSTask * appendTask = [client appendObject:append];
  18. [appendTask continueWithBlock:^id(OSSTask *task) {
  19. NSLog(@"objectKey: %@", append.objectKey);
  20. if (!task.error) {
  21. NSLog(@"append object success!");
  22. OSSAppendObjectResult * result = task.result;
  23. NSString * etag = result.eTag;
  24. long nextPosition = result.xOssNextAppendPosition;
  25. } else {
  26. NSLog(@"append object failed, error: %@" , task.error);
  27. }
  28. return nil;
  29. }];

上傳後回調通知

用戶端在上傳Object時可以指定OSS服務端在處理完上傳請求後,通知您的商務服務器,在該伺服器確認接收了該回調後將回調的結果返回給用戶端。因為加入了回調請求和響應的過程,相比簡單上傳,使用回調通知機制一般會導致用戶端花費更多的等待時間。

具體說明參考:Callback

程式碼範例:

  1. OSSPutObjectRequest * request = [OSSPutObjectRequest new];
  2. request.bucketName = @"<bucketName>";
  3. request.objectKey = @"<objectKey>";
  4. request.uploadingFileURL = [NSURL fileURLWithPath:@<filepath>"];
  5. // 設定回調參數
  6. request.callbackParam = @{
  7. @"callbackUrl": @"<your server callback address>",
  8. @"callbackBody": @"<your callback body>"
  9. };
  10. // 設定自訂變數
  11. request.callbackVar = @{
  12. @"<var1>": @"<value1>",
  13. @"<var2>": @"<value2>"
  14. };
  15. request.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
  16. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
  17. };
  18. OSSTask * task = [client putObject:request];
  19. [task continueWithBlock:^id(OSSTask *task) {
  20. if (task.error) {
  21. OSSLogError(@"%@", task.error);
  22. } else {
  23. OSSPutObjectResult * result = task.result;
  24. NSLog(@"Result - requestId: %@, headerFields: %@, servercallback: %@",
  25. result.requestId,
  26. result.httpResponseHeaderFields,
  27. result.serverReturnJsonString);
  28. }
  29. return nil;
  30. }];

分區上傳

因為篇幅的原因,分區上傳參考:分區上傳

斷點續傳

特別注意

  • 斷點續傳暫時只支援上傳本地檔案。

  • 對於移動端來說,如果不是比較大的檔案,不建議使用這種方式上傳,因為斷點續傳是通過分區上傳實現的,上傳單個檔案需要進行多次網路請求,效率不高。**

在無線網路下,上傳比較大的檔案期間長,可能會遇到因為網路條件差、使用者切換網路等原因導致上傳中途失敗,整個檔案需要重新上傳。為此,SDK提供了斷點上傳功能。

在上傳前,可以指定斷點記錄的保存檔案夾。若不進行此項設定,斷點上傳只在本次上傳生效,某個分區因為網路原因等上傳失敗時會進行重試,避免整個大檔案重新上傳,節省重試時間和耗用流量。如果設定了斷點記錄的保存檔案夾,如果任務失敗,在下次重新啟動任務,上傳同一檔案到同一Bucket、Object時,如果使用者佈建取消時不刪除斷點記錄。再次上傳將從斷點記錄處繼續上傳。詳見隨後的範例。

斷點續傳失敗時,如果同一任務一直得不到續傳,可能會在OSS上積累無用碎片。對這種情況,可以為Bucket設定lifeCycle規則,定時清理碎片。參考:生命週期管理

出於碎片管理的原因,如果在斷點續傳時取消當前任務。預設會同步清理已經上傳到伺服器的分區。如果取消時需要保留斷點上傳記錄,需要指定斷點記錄的保存檔案夾並修改deleteUploadIdOnCancelling參數。需要注意,如果本地保留記錄時間過長,且Bucket設定lifeCycle規則定時清理了服務端分區。會出現服務端和移動端記錄不一致的問題。

說明:

  • 斷點續傳的實現依賴InitMultipartUpload/UploadPart/ListParts/CompleteMultipartUpload/AbortMultipartUpload,如果採用STS鑒權模式,請注意加上這些API所需的許可權。

  • 斷點續傳也支援上傳後回調通知,用法和上述普通上傳回調通知一致。

  • 斷點續傳已經預設開啟每個分區上傳時的Md5校驗,請勿重複在request中設定Content-Md5頭部。

在本地持久保存斷點記錄的調用方式(預設是不設定)

  1. OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
  2. resumableUpload.bucketName = OSS_BUCKET_PRIVATE;
  3. //...
  4. NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  5. resumableUpload.recordDirectoryPath = cachesDir;

斷點續傳功能實現

  1. // 獲得UploadId進行上傳,如果任務失敗並且可以續傳,利用同一個UploadId可以上傳同一檔案到同一個OSS上的儲存物件
  2. OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
  3. resumableUpload.bucketName = <bucketName>;
  4. resumableUpload.objectKey = <objectKey>;
  5. resumableUpload.partSize = 1024 * 1024;
  6. resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
  7. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
  8. };
  9. NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  10. //設定斷點記錄檔案
  11. resumableUpload.recordDirectoryPath = cachesDir;
  12. //設定NO,取消時,不刪除斷點記錄檔案,如果不進行設定,預設YES,是會刪除斷點記錄檔案,下次再進行上傳時會重新上傳。
  13. resumableUpload.deleteUploadIdOnCancelling = NO;
  14. resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:<your file path>];
  15. OSSTask * resumeTask = [client resumableUpload:resumableUpload];
  16. [resumeTask continueWithBlock:^id(OSSTask *task) {
  17. if (task.error) {
  18. NSLog(@"error: %@", task.error);
  19. if ([task.error.domain isEqualToString:OSSClientErrorDomain] && task.error.code == OSSClientErrorCodeCannotResumeUpload) {
  20. // 該任務無法續傳,需要獲取新的uploadId重新上傳
  21. }
  22. } else {
  23. NSLog(@"Upload file success");
  24. }
  25. return nil;
  26. }];
  27. // [resumeTask waitUntilFinished];
  28. // [resumableUpload cancel];

資料完整性校驗

因為移動端網路環境的複雜性,OSS SDK提供了基於MD5和CRC64的端到端的資料完整性驗證功能。

MD5校驗

需要在上傳檔案時提供檔案的Content-MD5值,OSS伺服器會幫助使用者進行MD5校驗,只有在OSS伺服器計算已接收的檔案得到的MD5值和上傳提供的MD5一致時才可以上傳成功,從而保證上傳資料的完整性。

  1. OSSPutObjectRequest * request = [OSSPutObjectRequest new];
  2. request.bucketName = BUCKET_NAME;
  3. ...
  4. request.contentMd5 = [OSSUtil fileMD5String:filepath];

CRC校驗

與MD5相比,CRC64可以同時上傳並計算CRC值。

  1. // 構造上傳請求
  2. OSSPutObjectRequest * request = [OSSPutObjectRequest new];
  3. request.bucketName = OSS_BUCKET_PRIVATE;
  4. ///....
  5. request.crcFlag = OSSRequestCRCOpen;
  6. // 開啟crc效驗後。如果在傳輸中資料不一致,會提示OSSClientErrorCodeInvalidCRC 錯誤。
  7. OSSTask * task = [_client putObject:request];
  8. [[task continueWithBlock:^id(OSSTask *task) {
  9. //如果crc效驗失敗,會有error
  10. XCTAssertNil(task.error);
  11. return nil;
  12. }] waitUntilFinished];