The main idea is to create a blank file with the size of the target file, and then segment the data into this blank file.
You can get the exact size of the file in the server by sending a head request, and then split the length into chunks of data that are set by the GET request.
Request header information, you can determine the starting length and end length of the downloaded file in a single thread.
For example, the target file size 900M, when downloading, open three threads to download, size = 300. Then the first thread should be 0~~299m's task.
The second thread is the 300~~599m task, and the third is the last size of the 600m~~, and when it cannot be divisible, each size+1 to avoid causing errors.
When writing to the file (which is the side of the download side write), the file handle (Nsfilehandle) is moved to the end of the currently downloaded file and then written.
When the download is complete, you need to close the current file handle.
@interface zyfiledownload:nsobject{ BOOL _downloading;} Are you downloading @property (nonatomic, ReadOnly, getter=isdownloading) BOOL downloading;//target path, which is the storage path @property (nonatomic, copy) nsstring *goalpath;//download Resource url@property (nonatomic, copy) nsstring *urlstr;//download Progress @property (nonatomic, copy) void ( ^progresshandler) (double progress);//Start download-(void) start;//end download-(void) pause; @end #import "ZYFileDownLoad.h" @ Implementation Zyfiledownload@end
#import "ZYFileDownLoad.h" @interface zymultifiledownload:zyfiledownload@end#import "ZYMultiFileDownLoad.h" #import "ZYSingleDownLoad.h" #define Zymaxdownloadcount 3@interface zymultifiledownload () @property (nonatomic, Strong) Nsmutablearray *singledownloads; @property (nonatomic, assign) long long totallength; @end @implementation zymultifiledownload-(void) getfilesize{//Send a HEAD request to get specific information about the data in the server response header content-length Nsmutableurlrequest *request = [[Nsmutableurlrequest alloc] Initwithurl:[nsurl URLWithString:self.urlStr]]; Request. HttpMethod = @ "HEAD"; Nsurlresponse *response = nil; You can also send asynchronous requests for information [nsurlconnection sendsynchronousrequest:request returningresponse:&response Error:nil]; Get file size self.totallength = response.expectedcontentlength;} -(Nsmutablearray *) singledownloads{if (_singledownloads = = nil) {_singledownloads = [Nsmutablearray array]; [Self getfilesize]; A long long size = 0; Number of downloads per pathif (self.totallength% Zymaxdownloadcount = = 0) {size = Self.totallength/zymaxdownloadcount; } else{size = Self.totallength/zymaxdownloadcount + 1; }//Create n downloader for (int i = 0; i < Zymaxdownloadcount; i++) {Zysingledownload *singledow nload = [[Zysingledownload alloc] init]; Singledownload.urlstr = Self.urlstr; Singledownload.goalpath = Self.goalpath; Singledownload.beginlength = i * size; Singledownload.endlength = (i + 1) * SIZE-1; Singledownload.progresshandler = ^ (double progress) {//The Progress action can be set here}; [_singledownloads Addobject:singledownload]; Create a temporary file with size such as server file [[Nsfilemanager Defaultmanager] CreateFileAtPath:self.goalPath contents:nil attributes:ni L]; Let the length of the Self.goalpath file be self.totallengt nsfilehandle *writehandle = [Nsfilehandle filesHandleForWritingAtPath:self.goalPath]; [Writehandle TruncateFileAtOffset:self.totalLength]; }} return _singledownloads;} -(void) start{[self.singledownloads makeobjectsperformselector: @selector (start)]; _downloading = YES;} -(void) pause{[self.singledownloads makeobjectsperformselector: @selector (pause)]; _downloading = NO;} @end
@interface Zysingledownload:zyfiledownload@property (nonatomic, assign) a long long beginlength; @property (Nonatomic, Assign) long long endlength, @end #import "ZYSingleDownLoad.h" @interface zysingledownload () < Nsurlconnectiondatadelegate> @property (nonatomic, assign) long long currentlength; @property (nonatomic, Strong) Nsurlconnection *connection; @property (nonatomic, strong) Nsfilehandle *writehandle; @end @implementation zysingledownload-(Nsfilehandle *) writehandle{if (!_writehandle) {_writehandle = [Nsfilehandle fileHandleForWr ItingAtPath:self.goalPath]; } return _writehandle;} -(void) start{nsurl *url = [Nsurl URLWithString:self.urlStr]; Nsmutableurlrequest *request = [[Nsmutableurlrequest alloc] initwithurl:url]; Set the request body, starting from which data segment to download nsstring *values = [NSString stringwithformat:@ "Bytes=%lld-%lld", Self.beginlength + Self.currentlength,self.endlength]; [Request Setvalue:values forhttpheaderfield:@ "Range"]; Self.connection = [NsurlconneCtion Connectionwithrequest:request delegate:self]; _downloading = YES;} -(void) pause{[self.connection Cancel]; Self.connection = nil;} #pragma mark--------nsurlconnectiondatadelegate-(void) connection: (Nsurlconnection *) connection Didreceiveresponse :(Nsurlresponse *) response{}-(void) connection: (Nsurlconnection *) connection didreceivedata: (NSData *) data{//move to Text The tail of the piece [Self.writehandle seekToFileOffset:self.beginLength + self.currentlength]; Writes data starting at the current moving position (end of file) [Self.writehandle Writedata:data]; Cumulative length Self.currentlength + = Data.length; Print download Progress Double progress = (double) self.currentlength/(Self.endlength-self.beginlength); if (Self.progresshandler) {Self.progresshandler (progress); }}-(void) connectiondidfinishloading: (nsurlconnection *) connection{//emptying attribute value self.currentlength = 0; Close connection [Self.writehandle CloseFile]; Self.writehandle = nil;} -(void) connection: (Nsurlconnection *) connection Didfailwitherror: (Nserror *) error{} @end
Multi-threaded breakpoints in iOS development download large files