iOS-大文件分片上傳和斷點續(xù)傳

轉(zhuǎn)自:http://blog.csdn.NET/nndasdfg/article/details/51436731

總結(jié)一下大文件分片上傳和斷點續(xù)傳的問題。因為文件過大(比如1G以上),必須要考慮上傳過程網(wǎng)絡(luò)中斷的情況。http的網(wǎng)絡(luò)請求中本身就已經(jīng)具備了分片上傳功能鄙煤,當傳輸?shù)奈募容^大時癌幕,http協(xié)議自動會將文件切片(分塊),但這不是我們現(xiàn)在說的重點吩愧,我們要做的事是保證在網(wǎng)絡(luò)中斷后1G的文件已上傳的那部分在下次網(wǎng)絡(luò)連接時不必再重傳顾彰。所以我們本地在上傳的時候极阅,要將大文件進行分片,比如分成1024*1024B涨享,即將大文件分成1M的片進行上傳筋搏,服務器在接收后,再將這些片合并成原始文件厕隧,這就是分片的基本原理奔脐。斷點續(xù)傳要求本地要記錄每一片的上傳的狀態(tài),我通過三個狀態(tài)進行了標記(wait loading finish)栏账,當網(wǎng)絡(luò)中斷帖族,再次連接后栈源,從斷點處進行上傳挡爵。服務器通過文件名、總片數(shù)判斷該文件是否已全部上傳完成甚垦。
下面來說細節(jié):
1茶鹃、首先獲取文件(音視頻、圖片)
分兩種情況艰亮,一種是在相冊庫里直接獲取闭翩,一種是調(diào)用相機。如果是通過UIImagePickerView來獲绕!(細節(jié)不詳述疗韵,網(wǎng)上一大堆),我們會發(fā)現(xiàn)當你選定一個視頻的時候侄非,會出現(xiàn)圖1的壓縮頁面蕉汪,最后我們的app獲取的視頻就是這個經(jīng)過壓縮后的視頻(不是視頻庫里的原始視頻流译,這里有個注意點,操作完該壓縮視頻后記得釋放者疤,系統(tǒng)不會幫你釋放的福澡,需要你手動來操作,下面會說到)驹马,然后通過UIImagePickerView的協(xié)議方法中的

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

獲取視頻的Info

fileInfo = {
    UIImagePickerControllerMediaType = "public.movie";
    UIImagePickerControllerMediaURL = "file:///private/var/mobile/Containers/Data/Application/2AAE9E44-0E6D-4499-9AC3-93D44D8342EA/tmp/trim.F36EC46C-4219-43C8-96A7-FA7141AB64D2.MOV";
    UIImagePickerControllerReferenceURL = "assets-library://asset/asset.MOV?id=DEDA9406-3223-4F87-ABB2-98FB5F5EB9C4&ext=MOV";
}

UIImagePickerControllerMediaType是選取文件的類型革砸,如KUTTypeImage,KUTTypeMovie糯累。這里注意一下movie和video的區(qū)別算利,一個是有聲音的視頻文件,一個是沒有聲音的視頻文件泳姐,當然還有Audio是只有聲音沒有視頻笔时。UIImagePickerControllerMediaURL是視頻的URL(如果是相機拍攝的,那么這個就是原始拍攝得到的視頻仗岸;如果是在相冊庫里選擇的允耿,那就是壓縮之后生成的視頻),注意這個URL不指向相冊庫扒怖,通過這個URL你可以操作這個視頻如刪除较锡,拷貝等,可以獲取壓縮后的視頻的大小盗痒。UIImagePickerControllerReferenceURL是一個指向相冊的URL蚂蕴,官方的解釋是an NSURL that references an asset in the AssetsLibrary framework,通過這個URL俯邓,你可以獲取視頻的所有信息骡楼,包括文件名,縮略圖稽鞭,時長等(通過ALAssetsLibraryassetsLibraryassetForURL:referenceURLresultBlock:)鸟整。
如果是相機拍攝的,注意兩個保存方法:圖片保存到相冊:

assetsLibrarywriteImageDataToSavedPhotosAlbum:UIImageJPEGRepresentation([infovalueForKey:UIImagePickerControllerOriginalImage],(CGFloat)1.0)metadata:nilcompletionBlock: failureBlock:

高保真壓縮圖片的方法:

NSData * UIImageJPEGRepresentation ( UIImage *image, CGFloat compressionQuality)

視頻保存到相冊:

assetsLibrary writeVideoAtPathToSavedPhotosAlbum:MediaURL completionBlock:failureBlock:

到這里朦蕴,我們就獲取了所有需要的文件以及文件信息篮条。下面要做的就是將文件分片。

2吩抓、將獲取到的文件分片
首先涉茧,我將獲取到的文件保存在這這樣一個類中

@interface CNFile : NSObject
@property (nonatomic,copy)NSString* fileType;//image  or  movie
@property (nonatomic,copy)NSString* filePath;//文件在app中路徑
@property (nonatomic,copy)NSString* fileName;//文件名
@property (nonatomic,assign)NSInteger fileSize;//文件大小
@property (nonatomic,assign) NSInteger trunks;//總片數(shù)
@property (nonatomic,copy)NSString* fileInfo;
@property (nonatomic,strong)UIImage* fileImage;//文件縮略圖
@property (nonatomic,strong) NSMutableArray* fileArr;//標記每片的上傳狀態(tài)
@end

這樣我們就可以對每一個CNFile對象進行操作了。

-(void)readDataWithChunk:(NSInteger)chunk file:(CNFile*)file{
  總片數(shù)的獲取方法:
    int offset =1024*1024;(每一片的大小是1M)
    NSInteger chunks = (file.fileSize%1024==0)?((int)(file.fileSize/1024*1024)):((int)(file.fileSize/(1024*1024) + 1));
    NSLog(@"chunks = %ld",(long)chunks);
    將文件分片疹娶,讀取每一片的數(shù)據(jù):
    NSData* data;
    NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:file.filePath];
    [readHandle seekToFileOffset:offset * chunk];
    data = [readHandle readDataOfLength:offset];
}

這樣我們就獲取了每一片要上傳的數(shù)據(jù)伴栓,然后詢問服務器,該片是否已經(jīng)存在

(方法-(void)ifHaveData:(NSData*)data WithChunk:(NSInteger)chunk file:(CNFile*)file)

,如果存在钳垮,令chunk+1除师,重復上面的方法讀取下一片,直到服務器不存在該片扔枫,那么上傳該片數(shù)據(jù)汛聚。在這個方法中注意設(shè)置該chunk的上傳狀態(tài)(wait loading finish),這將關(guān)系到本地判斷該文件是否已全部上傳完成短荐。

下一步就是上傳的過程:

-(void)uploadData:(NSData*) data WithChunk:(NSInteger) chunk file:(CNFile*)file倚舀;

在服務器返回該片上傳成功后,我們要做的事有很多:
1)先將已經(jīng)成功上傳的本片的flag置finish

[file.fileArr replaceObjectAtIndex:chunk withObject:@“finish"];

2)查看是否所有片的flag都已經(jīng)置finish忍宋,如果都已經(jīng)finish痕貌,說明該文件上傳完成,那么刪除該文件糠排,上傳下一個文件或者結(jié)束舵稠。

for (NSInteger j =0; j<chunks; j++){
if (j == chunks || ((j == chunks -1)&&([file.fileArr[j] isEqualToString:@"finish"])))
     [me deleteFile:file.filePath];
     [me readNextFile];
}

3)如果沒有都finish,那么看本地下一chunk對應的flag是否是wait

 NSLog(@"查看第%ld片的狀態(tài)",chunk+1);
 for(NSInteger i = chunk+1;i < chunks;i++)
  {
     NSString* flag = [file.fileArrobjectAtIndex:i];
      if ([flagisEqualToString:@"wait"]) {
             [me readDataWithChunk:i  fileName:fileName file:file];
               break;
          }
   }

在第2入宦、3步之間可以有一個 2.5)判斷是否暫停上傳

if(me.isPause ==YES)
  {
  //將目前讀到了第幾個文件的第幾片保存到本地
     [self saveProgressWithChunk:chunk file:file];
      return ;
   }

這個操作實際上和上傳過程中斷網(wǎng)是一樣的哺徊,為了斷點續(xù)傳,在斷網(wǎng)或者暫停的時候乾闰,我們要將目前的進度保存起來落追,以便下次上傳時略過前面已置finish的片。
然后還有一個問題涯肩,如果我們就這樣線性的一片一片上傳轿钠,實際上失去了分片上傳的意義,應該結(jié)合多線程病苗,使分片上傳過程并發(fā)執(zhí)行疗垛,同時上傳多片,這樣就提高了上傳效率硫朦,并充分利用了網(wǎng)絡(luò)帶寬贷腕。

    dispatch_async(dispatch_queue_t queue, ^{
        [me readDataWithChunk: chunk];
    })

最后注意一下,每上傳完一個視頻阵幸,去設(shè)置里看看你的app占用的存儲空間有沒有增大哦花履,如果你沒有處理那個生成的壓縮視頻,你會發(fā)現(xiàn)你的app的空間占用量是很大的挚赊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市济瓢,隨后出現(xiàn)的幾起案子荠割,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔑鹦,死亡現(xiàn)場離奇詭異夺克,居然都是意外死亡,警方通過查閱死者的電腦和手機嚎朽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門铺纽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人哟忍,你說我怎么就攤上這事狡门。” “怎么了锅很?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵其馏,是天一觀的道長。 經(jīng)常有香客問我爆安,道長叛复,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任扔仓,我火速辦了婚禮褐奥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翘簇。我一直安慰自己抖僵,他們只是感情好,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布缘揪。 她就那樣靜靜地躺著耍群,像睡著了一般。 火紅的嫁衣襯著肌膚如雪找筝。 梳的紋絲不亂的頭發(fā)上蹈垢,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音袖裕,去河邊找鬼曹抬。 笑死,一個胖子當著我的面吹牛急鳄,可吹牛的內(nèi)容都是我干的谤民。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼疾宏,長吁一口氣:“原來是場噩夢啊……” “哼张足!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坎藐,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤为牍,失蹤者是張志新(化名)和其女友劉穎哼绑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碉咆,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡抖韩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了疫铜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茂浮。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖壳咕,靈堂內(nèi)的尸體忽然破棺而出席揽,到底是詐尸還是另有隱情,我是刑警寧澤囱井,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布驹尼,位于F島的核電站,受9級特大地震影響庞呕,放射性物質(zhì)發(fā)生泄漏新翎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一住练、第九天 我趴在偏房一處隱蔽的房頂上張望地啰。 院中可真熱鬧,春花似錦讲逛、人聲如沸亏吝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔚鸥。三九已至,卻和暖如春许赃,著一層夾襖步出監(jiān)牢的瞬間止喷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工混聊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留弹谁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓句喜,卻偏偏與公主長得像预愤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咳胃,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容