ASIHTTPRequest可以實現斷點續傳。網上有一些介紹類似使用:
[request setAllowResumeForFileDownloads:YES]; 方法的。但是它不是真正意義的斷點續傳。它只能讓應用在下載過程中,暫停和繼續。如果退出應用再進入是無效的。 不過,通過ASIHTTPRequest的異步請求以及delegate還是可以實現斷點續傳的。 本文還是以Grails編寫斷點續傳服務器端為例。 異步請求的代碼: -(void) doSimpleGetBinary{ NSURL *url = [NSURL URLWithString:@"http://localhost:8080/BookProto/book/image"]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setRequestMethod:@"GET"]; //[request addRequestHeader:@"Range" value:@"bytes=3-"]; [request setDelegate:self]; [request startAsynchronous]; } 這裡設置了Delegate, 要在頭文件中實現相應的protocol: @interface CFHttpDemoViewController : UIViewController<ASIProgressDelegate> { 本例中使用到了delegate的如下方法。 requestFinished: - (void)requestFinished:(ASIHTTPRequest *)request{ NSLog(@"response status code: %i",[request responseStatusCode]); NSLog(@"response content length: %@",[[request responseHeaders] objectForKey:@"Content-Length" ]); NSLog(@"request finished."); label.text=@"request finished."; } 這個方法在異步請求結束後調用。 下面的方法,是當緩沖區接收到部分數據後調用,看起來是每間隔一定的毫秒,就調用一下,並傳入緩沖區的NSData對象。 -(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data{ NSLog(@"did receive data, data length: %i",[data length]); //復制到字節數組中 Byte *byteData=(Byte *)malloc([data length]); memcpy(byteData,[data bytes],[data length]); for (int i=0; i<=10; i++) { NSLog(@"%i: %i",i+1,byteData[i]); } free(byteData); [request cancel]; label.text=@"canceled."; } 運行代碼,屏蔽: [request addRequestHeader:@"Range" value:@"bytes=3-"]; 和取消屏蔽,數據分別如下: 2011-07-12 14:17:13.497 CFHttpDemo[2647:207] did receive data, data length: 10172 2011-07-12 14:17:13.514 CFHttpDemo[2647:207] 1: 137 2011-07-12 14:17:13.515 CFHttpDemo[2647:207] 2: 80 2011-07-12 14:17:13.516 CFHttpDemo[2647:207] 3: 78 2011-07-12 14:17:13.516 CFHttpDemo[2647:207] 4: 71 2011-07-12 14:17:13.517 CFHttpDemo[2647:207] 5: 13 2011-07-12 14:17:13.518 CFHttpDemo[2647:207] 6: 10 2011-07-12 14:17:13.518 CFHttpDemo[2647:207] 7: 26 2011-07-12 14:17:13.519 CFHttpDemo[2647:207] 8: 10 2011-07-12 14:17:13.520 CFHttpDemo[2647:207] 9: 0 2011-07-12 14:17:13.520 CFHttpDemo[2647:207] 10: 0 2011-07-12 14:17:13.521 CFHttpDemo[2647:207] 11: 0 2011-07-12 14:17:13.522 CFHttpDemo[2647:207] response status code: 200 2011-07-12 14:17:13.523 CFHttpDemo[2647:207] response content length: 10172 2011-07-12 14:17:13.523 CFHttpDemo[2647:207] request finished. 2011-07-12 14:02:24.551 CFHttpDemo[2578:207] did receive data, data length: 10169 2011-07-12 14:02:24.553 CFHttpDemo[2578:207] byteData ok. 2011-07-12 14:02:24.554 CFHttpDemo[2578:207] 1: 71 2011-07-12 14:02:24.554 CFHttpDemo[2578:207] 2: 13 2011-07-12 14:02:24.555 CFHttpDemo[2578:207] 3: 10 2011-07-12 14:02:24.555 CFHttpDemo[2578:207] 4: 26 2011-07-12 14:02:24.556 CFHttpDemo[2578:207] 5: 10 2011-07-12 14:02:24.556 CFHttpDemo[2578:207] 6: 0 2011-07-12 14:02:24.557 CFHttpDemo[2578:207] 7: 0 2011-07-12 14:02:24.557 CFHttpDemo[2578:207] 8: 0 2011-07-12 14:02:24.558 CFHttpDemo[2578:207] 9: 13 2011-07-12 14:02:24.558 CFHttpDemo[2578:207] 10: 73 2011-07-12 14:02:24.560 CFHttpDemo[2578:207] 11: 72 2011-07-12 14:02:24.561 CFHttpDemo[2578:207] response status code: 206 2011-07-12 14:02:24.561 CFHttpDemo[2578:207] response content length: 10169 2011-07-12 14:02:24.562 CFHttpDemo[2578:207] request finished. 2. NSUrlConnection實現斷點續傳的關鍵是自定義http request的頭部的range域屬性。 Range頭域 Range頭域可以請求實體的一個或者多個子范圍。例如, 表示頭500個字節:bytes=0-499 表示第二個500字節:bytes=500-999 表示最後500個字節:bytes=-500 表示500字節以後的范圍:bytes=500- 第一個和最後一個字節:bytes=0-0,-1 同時指定幾個范圍:bytes=500-600,601-999 但是服務器可以忽略此請求頭,如果無條件GET包含Range請求頭,響應會以狀態碼206(PartialContent)返回而不是以200(OK)。 在ios中使用NSMutableURLRequest來定義頭部域 NSURL *url1=[NSURL URLWithString:@"下載地址"; NSMutableURLRequest* request1=[NSMutableURLRequest requestWithURL:url1]; [request1 setValue:@"bytes=20000-" forHTTPHeaderField:@"Range"]; [request1 setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; NSData *returnData1 = [NSURLConnection sendSynchronousRequest:request1 returningResponse:nil error:nil]; [self writeToFile:returnData1 fileName:@"SOMEPATH"]; -(void)writeToFile:(NSData *)data fileName:(NSString *) fileName { NSString *filePath=[NSString stringWithFormat:@"%@",fileName]; if([[NSFileManager defaultManager] fileExistsAtPath:filePath] == NO){ NSLog(@"file not exist,create it..."); [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; }else { NSLog(@"file exist!!!"); } FILE *file = fopen([fileName UTF8String], [@"ab+" UTF8String]); if(file != NULL){ fseek(file, 0, SEEK_END); } int readSize = [data length]; fwrite((const void *)[data bytes], readSize, 1, file); fclose(file); }