最近在做視頻音樂方面的東西,整理一下下載文件相關內容
功能需求:
下載文件,可以顯示進度,暫停,繼續,斷點續傳
1、首先下載文件相關代碼:有三個回調方法:下載進度,下載成功,下載失敗
要說明的是下載進度顯示:在一個tableview中顯示正在下載的文件,分爲:1)存儲下載文件信息(名字,圖片鏈接,下載地址,文件格式,文件大小等)。2)實時更新進度條,我個人是創建了一個單例,存儲下載地址和下載進度,key值爲地址 ,value爲進度;然後把多個鍵值對存到單例的數組中,然後在下載中心取出來,對cell單獨進行更新
NSFileManager *fileManager = [NSFileManager defaultManager];
//檢查本地文件是否已存在
NSString *fileName = [NSString stringWithFormat:@"%@/%@.mp4", aSavePath, aFileName];
//檢查附件是否存在
if ([fileManager fileExistsAtPath:fileName]) {
NSData *audioData = [NSData dataWithContentsOfFile:fileName];
[self showHoderTopView:@"已經加入您的緩存"];
// [self requestFinished:[NSDictionary dictionaryWithObject:audioData forKey:@"res"] tag:aTag];
}else{
//創建附件存儲目錄
if (![fileManager fileExistsAtPath:aSavePath]) {
[fileManager createDirectoryAtPath:aSavePath withIntermediateDirectories:YES attributes:nil error:nil];
}
//下載附件
NSURL *url = [[NSURL alloc] initWithString:aUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.inputStream = [NSInputStream inputStreamWithURL:url];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:fileName append:NO];
//下載進度控制
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSString *progress = [NSString stringWithFormat:@"%f",(float)totalBytesRead/totalBytesExpectedToRead];
}];
//已完成下載
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
[self showHoderTopView:@"緩存成功"];
NSData *audioData = [NSData dataWithContentsOfFile:fileName];
NSString *byte = [NSString stringWithFormat:@"%d",audioData.length];
//設置下載數據到res字典對象中並用代理返回下載數據NSData
// [self requestFinished:[NSDictionary dictionaryWithObject:audioData forKey:@"res"] tag:aTag];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//下載失敗
//[self requestFailed:aTag];
}];
[operation start];
2、暫停和繼續和取消
AFHTTPRequestOperation對象方法分別對應 pause resume cancel 。問題在於怎麼獲取到這個對象,我用的方法比較粗糙,就是存儲了這個對象到剛纔的單例中,關鍵字也是下載鏈接,只要這個對象存活就能拿到並進行操作。如果對象不存在又要繼續剛纔的任務,接下來就是斷點續傳了
3、斷點續傳
找了很多有關斷點續傳的資料,這篇博客的簡單實用
來自CSDN博客:AFNetworking實現程序重新啓動時的斷點續傳 http://blog.csdn.net/zhaoxy2850/article/details/21383515
//獲取已下載的文件大小
- (unsigned long long)fileSizeForPath:(NSString *)path {
signed long long fileSize = 0;
NSFileManager *fileManager = [NSFileManager new]; // default is not thread safe
if ([fileManager fileExistsAtPath:path]) {
NSError *error = nil;
NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
if (!error && fileDict) {
fileSize = [fileDict fileSize];
}
}
return fileSize;
}
//開始下載
- (void)startDownload {
NSString *downloadUrl = @"http://www.xxx.com/xxx.zip";
NSString *cacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *downloadPath = [cacheDirectory stringByAppendingPathComponent:@"xxx.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl]];
//檢查文件是否已經下載了一部分
unsigned long long downloadedBytes = 0;
if ([[NSFileManager defaultManager] fileExistsAtPath:downloadPath]) {
//獲取已下載的文件長度
downloadedBytes = [self fileSizeForPath:downloadPath];
if (downloadedBytes > 0) {
NSMutableURLRequest *mutableURLRequest = [request mutableCopy];
NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
[mutableURLRequest setValue:requestRange forHTTPHeaderField:@"Range"];
request = mutableURLRequest;
}
}
//不使用緩存,避免斷點續傳出現問題
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
//下載請求
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
//下載路徑
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:downloadPath append:YES];
//下載進度回調
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//下載進度
float progress = ((float)totalBytesRead + downloadedBytes) / (totalBytesExpectedToRead + downloadedBytes);
}];
//成功和失敗回調
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
}