iOS 文件下载及上传

来源:互联网 发布:尼特罗会长知乎 编辑:程序博客网 时间:2024/05/17 23:47

1.下载文件及暂停、断点续传
.h文件

+(void)downloadFileWithOption:(NSDictionary *)paramDic requestURL:(NSString*)requestURL savedPath:(NSString*)savedPath progress:(void (^)(float progress))progress downloadSuccess:(void (^)(id responseObject))success downloadFailure:(void (^)(NSError *error))failure;

.m文件实现

+(void)downloadFileWithOption:(NSDictionary *)paramDic requestURL:(NSString*)requestURL savedPath:(NSString*)savedPath progress:(void (^)(float progress))progress downloadSuccess:(void (^)(id responseObject))success downloadFailure:(void (^)(NSError *error))failure

{

    AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializerserializer];

    NSMutableURLRequest *request =[serializerrequestWithMethod:@"POST"URLString:requestURLparameters:paramDicerror:nil];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperationalloc]initWithRequest:request];

    [operation setOutputStream:[NSOutputStreamoutputStreamToFileAtPath:savedPathappend:NO]];

    [operation setDownloadProgressBlock:^(NSUInteger bytesRead,longlong totalBytesRead,longlong totalBytesExpectedToRead) {

        float p = (float)totalBytesRead / totalBytesExpectedToRead;

        progress(p);

    }];

    

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation,id responseObject) {

        

        success(responseObject);

        

    } failure:^(AFHTTPRequestOperation *operation,NSError *error) {

        

        failure(error);

        

    }];

    

    [operation start];

    

}

使用

 NSString *url =@"http://139.129……………………………………";

    NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);

    NSString *documentsDirectory = [pathsobjectAtIndex:0];

    NSString* path = [documentsDirectorystringByAppendingPathComponent:@"test.bin"];

    [UrlConnectiondownloadFileWithOption:nil

                               requestURL:url

                                savedPath:path

                                 progress:^(float progress) {

                                     NSLog(@"当前下载 %f",progress);

                                                      }

                          downloadSuccess:^(id responseObject){

                              NSLog(@"下载成功");

                              

                              NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);

                                      NSString *documentsDirectory = [pathsobjectAtIndex:0];

                                      NSString* path = [documentsDirectorystringByAppendingPathComponent:@"test.bin"];

                              

                              

                                      NSMutableData *file = [NSMutableData dataWithContentsOfFile:path];

                                      NSLog(@"-----%lu",(unsignedlong)file.length);

                          }

                          downloadFailure:^(NSError *error)

     {

     }];

简单思路:通过重组progressBlock , successBlock ,requestUrl ,outPutStream,然后利用AFNetworking自带的pause,resume即可妥妥的实现。

不过碰到了一些问题也挺折磨人的,文件输入流,初始化就碰到问题了,
1.[self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:YES]
如果追加了原始文件的data,就无法在下载过程中从outPutStream中获取到data。
 [self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:NO]
如果不追加,续传就成覆盖了。 

官方文档也没仔细看,所幸就使用不追加的方式,然后手动同步文件与输入流。 方法如下

-(void)readCacheToOutStreamWithPath:(NSString*)path;

2.pause之后,AFHTTPRequestOperation.
totalBytesRead,仍然记录这之前的读取长度,如果resume了,这是content-length发生了变法,这个时候就需要从组progressBlock了,同时也需要将totalBytesRead设为0,因为是私有属性,所以就用KVC。

          [self.requestOperation setValue:@"0" forKey:@"totalBytesRead"];


------------随便贴个VC----------------------

#define Vedio @"http://221.228.249.82/youku/697A5CA0CEB3582FB91C4E3A88/03002001004E644FA2997704E9D2A7BA1E7B9D-6CAB-79A9-E635-3B92A92B3500.mp4"


#define Picture @"http://x1.zhuti.com/down/2012/11/29-win7/3D-1.jpg"

- (IBAction)download:(id)sender

{

//http://202.102.88.133/youku/657114D0FE44481C592F964ABD/030020010053F4AB5FB92A01296A84C7E5A401-0FC6-BD65-4525-706B419E9EA6.mp4

//    http://b.hiphotos.baidu.com/image/h%3D1200%3Bcrop%3D0%2C0%2C1920%2C1200/sign=b284ea7541a98226a7c12f25bab28262/960a304e251f95ca8888fab6cb177f3e670952b4.jpg

    NSString* path = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/temp"];

    NSLog(@"path = %@",path);

    operation = [[DownLoadOperationallocinit];

    [operationdownloadWithUrl:Picture

                     cachePath:^NSString *{

                         return path;

                     } progressBlock:^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead) {

                         

                         NSLog(@"bytesRead = %u ,totalBytesRead = %llu totalBytesExpectedToRead = %llu",bytesRead,totalBytesRead,totalBytesExpectedToRead);

                         float progress = totalBytesRead / (float)totalBytesExpectedToRead;

                         

                         [self.progressViewsetProgress:progressanimated:YES];

                         

                         [self.labelsetText:[NSStringstringWithFormat:@"%.2f%%",progress*100]];

                         UIImage* image = [UIImageimageWithData:operation.requestOperation.responseData];

                         [self.imageViewsetImage:image];

                     } success:^(AFHTTPRequestOperation *operation,id responseObject) {

                         

                         NSLog(@"success");

//                         UIImage* image = [UIImage imageWithData:operation.responseData];

//                         [self.imageView setImage:image];

                         

                         

                         

                     } failure:^(AFHTTPRequestOperation *operation,NSError *error) {

                         NSLog(@"error = %@",error);

                     }];


    

    

}



----------------------------------












#import <Foundation/Foundation.h>

#import "AFNetworking.h"



@interface DownLoadOperation :NSObject


@property(nonatomic ,strongNSURL* url;

@property(nonatomic ,copyNSString* (^cachePath)(void);

@property(nonatomic ,strongAFHTTPRequestOperation* requestOperation;

@property(nonatomic ,copyvoid(^progressBlock)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead);



-(void)downloadWithUrl:(id)url

             cachePath:(NSString* (^) (void))cacheBlock

         progressBlock:(void (^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))progressBlock

               success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success

               failure:(void (^)(AFHTTPRequestOperation *operation,NSError *error))failure;


@end




#import "DownLoadOperation.h"


@implementation DownLoadOperation


-(void)downloadWithUrl:(id)url

             cachePath:(NSString* (^) (void))cacheBlock

         progressBlock:(void (^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))progressBlock

               success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success

               failure:(void (^)(AFHTTPRequestOperation *operation,NSError *error))failure

{

    

    self.cachePath = cacheBlock;

    //获取缓存的长度

    longlong cacheLength = [[selfclasscacheFileWithPath:self.cachePath()];

    

    NSLog(@"cacheLength = %llu",cacheLength);

    

    //获取请求

    NSMutableURLRequest* request = [[selfclassrequestWithUrl:urlRange:cacheLength];

    

    

    self.requestOperation = [[AFHTTPRequestOperationallocinitWithRequest:request];

    [self.requestOperationsetOutputStream:[NSOutputStreamoutputStreamToFileAtPath:self.cachePath()append:NO]];

    

    //处理流

    [selfreadCacheToOutStreamWithPath:self.cachePath()];

    

    

    [self.requestOperationaddObserver:selfforKeyPath:@"isPaused"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];

  

    

    //获取进度块

    self.progressBlock = progressBlock;

    

    

    //重组进度block

    [self.requestOperationsetDownloadProgressBlock:[selfgetNewProgressBlockWithCacheLength:cacheLength]];

    

    

    //获取成功回调块

    void (^newSuccess)(AFHTTPRequestOperation *operation,id responseObject) = ^(AFHTTPRequestOperation *operation,idresponseObject){

        NSLog(@"responseHead = %@",[operation.responseallHeaderFields]);

        

        success(operation,responseObject);

    };


    

    [self.requestOperationsetCompletionBlockWithSuccess:newSuccess

                                                 failure:failure];

    [self.requestOperationstart];

    

    

}



#pragma mark - 获取本地缓存的字节

+(longlong)cacheFileWithPath:(NSString*)path

{

    NSFileHandle* fh = [NSFileHandlefileHandleForReadingAtPath:path];

    

    NSData* contentData = [fhreadDataToEndOfFile];

    return contentData ? contentData.length :0;

    

}



#pragma mark - 重组进度块

-(void(^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))getNewProgressBlockWithCacheLength:(longlong)cachLength

{

    typeof(self)newSelf =self;

    void(^newProgressBlock)(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead) = ^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead)

    {

        NSData* data = [NSDatadataWithContentsOfFile:self.cachePath()];

        [self.requestOperationsetValue:dataforKey:@"responseData"];

//        self.requestOperation.responseData = ;

        newSelf.progressBlock(bytesRead,totalBytesRead + cachLength,totalBytesExpectedToRead + cachLength);

    };

    

    return newProgressBlock;

}




#pragma mark - 读取本地缓存入流

-(void)readCacheToOutStreamWithPath:(NSString*)path

{

    NSFileHandle* fh = [NSFileHandlefileHandleForReadingAtPath:path];

    NSData* currentData = [fhreadDataToEndOfFile];

    

    if (currentData.length) {

        //打开流,写入data未打卡查看 streamCode = NSStreamStatusNotOpen

        [self.requestOperation.outputStreamopen];

        

        NSInteger       bytesWritten;

        NSInteger       bytesWrittenSoFar;

        

        NSInteger  dataLength = [currentDatalength];

        constuint8_t * dataBytes  = [currentDatabytes];

        

        bytesWrittenSoFar = 0;

        do {

            bytesWritten = [self.requestOperation.outputStreamwrite:&dataBytes[bytesWrittenSoFar]maxLength:dataLength - bytesWrittenSoFar];

            assert(bytesWritten !=0);

            if (bytesWritten == -1) {

                break;

            } else {

                bytesWrittenSoFar += bytesWritten;

            }

        } while (bytesWrittenSoFar != dataLength);

        

        

    }

}


#pragma mark - 获取请求


+(NSMutableURLRequest*)requestWithUrl:(id)url Range:(longlong)length

{

    NSURL* requestUrl = [urlisKindOfClass:[NSURLclass]] ? url : [NSURLURLWithString:url];

    

    NSMutableURLRequest* request = [NSMutableURLRequestrequestWithURL:requestUrl

                                                          cachePolicy:NSURLRequestReloadIgnoringCacheData

                                                      timeoutInterval:5*60];

    

    

    if (length) {

        [request setValue:[NSStringstringWithFormat:@"bytes=%lld-",length]forHTTPHeaderField:@"Range"];

    }

    

    NSLog(@"request.head = %@",request.allHTTPHeaderFields);

    

    return request;


}




#pragma mark - 监听暂停

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context

{

    NSLog(@"keypath = %@ changeDic = %@",keyPath,change);

    //暂停状态

    if ([keyPathisEqualToString:@"isPaused"] && [[changeobjectForKey:@"new"]intValue] ==1) {

        

       

        

        longlong cacheLength = [[selfclasscacheFileWithPath:self.cachePath()];

        //暂停读取data从文件中获取到NSNumber

        cacheLength = [[self.requestOperation.outputStreampropertyForKey:NSStreamFileCurrentOffsetKey]unsignedLongLongValue];

        NSLog(@"cacheLength = %lld",cacheLength);

        [self.requestOperationsetValue:@"0"forKey:@"totalBytesRead"];

        //重组进度block

        [self.requestOperationsetDownloadProgressBlock:[selfgetNewProgressBlockWithCacheLength:cacheLength]];

    }

}





@end




2.上传文件

+ (void)uploadFileWithOption:(NSDictionary *)paramDic requestURL:(NSString*)requestURL fileData:(NSData*)fileData progress:(void (^)(float progress))progress uploadSuccess:(void (^)(id responseObject))success uploadFailure:(void (^)(NSError *error))failure

{

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

    

    AFHTTPRequestOperation *operation = [manager POST:requestURL parameters:paramDic constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

        [formData appendPartWithFileData:fileData name:@"file" fileName:@"test.bin" mimeType:@""];

    } success:^(AFHTTPRequestOperation *operation, id responseObject) {

        success(responseObject);

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        failure(error);

    }];

    

    [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten,longlong totalBytesExpectedToWrite) {

        float p = (float)totalBytesWritten / totalBytesExpectedToWrite;

        progress(p);

    }];

}

************************************************************************************************************************

直接用NSURLConnection下载

#import "ViewController.h"

#import "DACircularProgressView.h"

/**

 

 *  NSURLConnectionDataDelegate协议中的代理方法

 开始接收到服务器的响应时调用

 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

 

 接收到服务器返回的数据时调用(服务器返回的数据比较大时会调用多次)

 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;

 

 服务器返回的数据完全接收完毕后调用

 - (void)connectionDidFinishLoading:(NSURLConnection *)connection;

 

 请求出错时调用(比如请求超时)

 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;


 */


@interface ViewController () <NSURLConnectionDataDelegate>

/**

 *  用来写数据的文件句柄对象

 */

@property (nonatomic,strong)NSFileHandle *writeHandle;

/**

 *  文件的总大小

 */

@property (nonatomic,assign)longlong totalLength;

/**

 *  当前已经写入的文件大小

 */

@property (nonatomic,assign)longlong currentLength;


@property (nonatomic,weak)DACircularProgressView *circleView;//用这个类来添加下载进度条

@end


@implementation HMViewController


- (void)viewDidLoad

{

    [superviewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

    /**

     *  DACircularProgress这个类添加下载进度条

     */

    DACircularProgressView *circleView = [[DACircularProgressViewalloc]init];

    circleView.frame = CGRectMake(10050100100);

    circleView.progressTintColor = [UIColorredColor];

    circleView.trackTintColor = [UIColorblueColor];

    circleView.progress = 0.01;

    [self.viewaddSubview:circleView];

    self.circleView = circleView;

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    // 1.URL

    NSURL *url = [NSURLURLWithString:@"http://hd.shijue.cvidea.cn/tf/140422/2330218/5355ca2

f3dfae93acb000001.JPEG"];

    // 2.请求

    NSURLRequest *request = [NSURLRequestrequestWithURL:url];

    // 3.下载(创建完conn对象后,会自动发起一个异步请求)

    [NSURLConnectionconnectionWithRequest:requestdelegate:self];

}

#pragma mark - NSURLConnectionDataDelegate代理方法

/**

 *  请求失败时调用(请求超时、网络异常)

 *

 *  @param error      错误原因

 */

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

    NSLog(@"didFailWithError");

}

/**

 *  1.接收到服务器的响应就会调用 (先搞一个0kb的文件,然后用writeHandle关联那个文件,最后写入数据

 *  @param response   响应

 */

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    // 文件路径 沙盒中的caches的路径

    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];

    NSLog(@"caches = %@",caches);


    //用这个stringByAppendingPathComponent:方法会自动添加一个/表示这是个路径

    NSString *filepath = [cachesstringByAppendingPathComponent:@"photodownload.JPEG"];//先搞一个0kb的文件

    // 创建一个空的文件沙盒中

    NSFileManager *mgr = [NSFileManagerdefaultManager];

    [mgr createFileAtPath:filepathcontents:nilattributes:nil];

    

    // 创建一个用来写数据的文件句柄

    self.writeHandle = [NSFileHandlefileHandleForWritingAtPath:filepath];//然后用writeHandle关联那个文件

    // 获得文件的总大小

    self.totalLength = response.expectedContentLength;

}


/**

 *  2.当接收到服务器返回的实体数据时调用(具体内容,这个方法可能会被调用多次)

 *

 *  @param data       这次返回的数据

 */

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data

{

    // 移动到文件的最后面

    [self.writeHandleseekToEndOfFile];

    

    // 将数据写入沙盒(先移动到最后面再拼接)

    [self.writeHandlewriteData:data]; //最后写入数据

    

    // 累计文件的长度

    self.currentLength += data.length;

    

    NSLog(@"下载进度:%f", (double)self.currentLength/self.totalLength);

    self.circleView.progress = (double)self.currentLength/self.totalLength;

}

/**

 *  3.加载完毕后调用(服务器的数据已经完全返回后)

 */

- (void)connectionDidFinishLoading:(NSURLConnection *)connection

{

    self.currentLength =0;

    self.totalLength =0;

    

    // 关闭文件

    [self.writeHandlecloseFile];

    self.writeHandle =nil;

}




0 0
原创粉丝点击