Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

25、26、27day-文件上传和下载&ASI&AFN

$
0
0

一、文件上传下载

1、小文件下载

直接用NSData的+ (id)dataWithContentsOfURL:(NSURL *)url;
利用NSURLConnection发送一个HTTP请求去下载
如果是下载图片,还可以利用SDWebImage框架
2、 HTTP Range

通过设置请求头Range可以指定每次从网路下载数据包的大小—–可以用于断点下载

 [request setValue:[NSString stringWithFormat:@"bytes=%lld-",self.currentDataLength] forHTTPHeaderField:@"Range"];

1)Range示例

bytes=0-4990499的头500个字节
 bytes=500-999500999的第二个500字节
bytes=500-  从500字节以后的所有字节
bytes=-500  最后500个字节
bytes=500-599,800-899  同时指定几个范围 

2)Range小结
- 用于分隔
前面的数字表示起始字节数
后面的数组表示截止字节数,没有表示到末尾
用于分组,可以一次指定多个Range,不过很少用

第三方解压缩框架——SSZipArchive

Adding to your project

Add SSZipArchive.h, SSZipArchive.m, and minizip to your project.
Add the libz library to your target 需要引入libz.dylib框架

Usage

// Unzipping
NSString *zipPath = @"path_to_your_zip_file";
NSString *destinationPath = @"path_to_the_folder_where_you_want_it_unzipped";
[SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath];

// Zipping
NSString *zippedPath = @"path_where_you_want_the_file_created";
NSArray *inputPaths = [NSArray arrayWithObjects:
                       [[NSBundle mainBundle] pathForResource:@"photo1" ofType:@"jpg"],
                       [[NSBundle mainBundle] pathForResource:@"photo2" ofType:@"jpg"]
                       nil];
[SSZipArchive createZipFileAtPath:zippedPath withFilesAtPaths:inputPaths];

4、multipart/form-data格式小结 --文件上传

设置Post的请求头(key value)

/*Content-Type   multipart/form-data; boundary=本次上传标示字符串(不能中文)*/
[request setValue:@"multipart/form-data;boundary=hisun" forHTTPHeaderField:@"Content-Type"];

The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/.

文件上传的请求体中包含的内容

这里写图片描述

请求参数
文件参数 
--本次上传标示字符串(边界比请求头的boundary 增加--开头)
Content-Disposition: form-data;  name="参数名"; filename="文件名"  
Content-Type: MIMEType  (文件类型)
文件具体数据

非文件参数 
--本次上传标示字符串(--边界)
Content-Disposition: form-data;  name="参数名称";  
参数值
--边界–(结尾标记 )

结尾标记(--边界--)

代码块

zip 压缩文件夹

NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
   NSString *filePath = [cachePath stringByAppendingPathComponent:@"images"];
   NSString *zipPath = [cachePath stringByAppendingPathComponent:@"images.zip"];
   NSLog(@"%@,%@",filePath,zipPath);
   [SSZipArchive createZipFileAtPath:zipPath withContentsOfDirectory:filePath];

根据URL 获取mimeType

- (NSString *) mimeTypeWithUrl:(NSURL *)url{
    NSURLResponse *response;
    [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:&response error:nil];
    return response.MIMEType;
}

//    NSString *mimetype = [self mimeTypeWithUrl:[NSURL fileURLWithPath:@"/Users/devzkn/Desktop/minion_02.png"]];

使用NSMutableURLRequest文件上传

#define HSBasicUrl  @"http://127.0.0.1:8080/KNServer/"

#define HSUrl(name) [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",HSBasicUrl,name]]

#define HSFileBoundary @"hisun"

#define HSFileEndedBounary [NSString stringWithFormat:@"--%@--",HSFileBoundary]

#define HSFileStartBoundary [NSString stringWithFormat:@"--%@",HSFileBoundary]

#define HSNewLine @"\r\n"

#define HSStringEncoding(str) [str dataUsingEncoding:NSUTF8StringEncoding]
#pragma mark - 文件上传

- (void)upload:(NSString*)fileName mimeType:(NSString *)mimeType fileData:(NSData*)fileData params:(NSDictionary*)params{

    //设置请求体

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:HSUrl(@"upload")];

    //准备请求体数据

    NSMutableData *data =[NSMutableData data];

    /*

     请求体:

     1)文件参数

     --本次上传标示字符串(边界)

     Content-Disposition: form-data;  name="参数名"; filename="文件名"

     Content-Type: MIMEType  (文件类型)

     文件具体数据



     2)非文件参数

     --本次上传标示字符串(边界)

     Content-Disposition: form-data;  name="参数名称"

     参数值

     3)边界–(结尾标记 )

     */

    [data appendData:HSStringEncoding(HSFileStartBoundary)];//分界线

    [data appendData:HSStringEncoding(HSNewLine)];

    NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"",@"file",fileName];

    [data appendData:HSStringEncoding(disposition)];//参数名

    [data appendData:HSStringEncoding(HSNewLine)];

    NSString *mimeTypeStr = [NSString stringWithFormat:@"Content-Type:%@",mimeType];

    [data appendData:HSStringEncoding(mimeTypeStr)];

    [data appendData:HSStringEncoding(HSNewLine)];



    [data appendData:HSStringEncoding(HSNewLine)];

    [data appendData:fileData];

    [data appendData:HSStringEncoding(HSNewLine)];

    //设置非文件数据

    [params enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

        [data appendData:HSStringEncoding(HSFileStartBoundary)];//分界线

        [data appendData:HSStringEncoding(HSNewLine)];



        NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"",key];

        [data appendData:HSStringEncoding(disposition)];//参数名

        [data appendData:HSStringEncoding(HSNewLine)];





        [data appendData:HSStringEncoding(HSNewLine)];

        [data appendData:HSStringEncoding([obj description])];

        [data appendData:HSStringEncoding(HSNewLine)];

    }];

    //结尾

    [data appendData:HSStringEncoding(HSFileEndedBounary)];

    [data appendData:HSStringEncoding(HSNewLine)];

    [request setHTTPBody:data];

    [request setHTTPMethod:@"post"];

    [request setValue:[NSString stringWithFormat:@"multipart/form-data;boundary=%@",HSFileBoundary] forHTTPHeaderField:@"Content-Type"];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {

        NSLog(@"%@,%@",response,[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]);

    }];


}

NSURLSession-断点续传

- (NSURLSession *)session{
    if (_session == nil) {
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue] ];
    }
    return _session;
}
#pragma mark - 断点下载
- (IBAction)pause:(UIButton *)sender {
    [sender setSelected:!sender.selected];
    if (sender.selected) {
        if (self.task == nil) {
            if (self.resumeData) {
                [self resumeDownLoad];//继续下载
            }else{
                [self startSessionWithConfiguration];//开始下载
            }
        }
    }else{
        [self pauseDownload];//暂停
    }
}
#pragma mark - NSURLSessionDownloadDelegate 查看下载进度
- (void) startSessionWithConfiguration{
    NSLog(@"%s----start ",__func__);
    [self.circularProgressView setProgress:0];
    [self.button setSelected:YES];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:HSURL(@"resources/videos/iPhoneSimulator6.1.sdk.zip")];
    self.task = [self.session downloadTaskWithRequest:request];
    [self.task resume];//执行任务

}
- (void)resumeDownLoad{
    if (self.resumeData == nil) {
        return;
    }
    NSLog(@"%s-----继续",__func__);
    self.task = [self.session downloadTaskWithResumeData:self.resumeData];
    [self.task resume];
    self.resumeData = nil;

}
- (void)pauseDownload {
    NSLog(@"%s------   暂停",__func__);
    if (self.task == nil) {
        return;
    }
    /*
     A completion handler that is called when the download has been successfully canceled.
     If the download is resumable, the completion handler is provided with a resumeData object. Your app can later pass this object to a session’s downloadTaskWithResumeData: or downloadTaskWithResumeData:completionHandler: method to create a new task that resumes the download where it left off.即包含了创建链接的URL和连接的头信息(Range)
     */
    HSweakself(weakself);
    [self.task  cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
        weakself.resumeData = resumeData;
        weakself.task = nil;
    }];
}

/* Sent when a download task that has completed a download.  The delegate should

 * copy or move the file at the given location to a new location as it will be

 * removed when the delegate message returns. URLSession:task:didCompleteWithError: will

 * still be called.

 */

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
    NSString *filePath = HSCachePath(downloadTask.response.suggestedFilename);
    NSLog(@"%s----%@ --%@ --%@",__func__,downloadTask.response,filePath,location.path);
    //移动location文件到filePath
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager moveItemAtPath:location.path toPath:filePath error:nil];


}
/* Sent periodically to notify the delegate of download progress. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    NSLog(@"%s----%@,bytesWritten:%lld,------totalBytesWritten:%lld,------totalBytesExpectedToWrite:%lld------%f%%",__func__,downloadTask,bytesWritten,totalBytesWritten,totalBytesExpectedToWrite,(double)totalBytesWritten*100.0/totalBytesExpectedToWrite);
    [self.circularProgressView setProgress:(double)totalBytesWritten*1.0/totalBytesExpectedToWrite];


}

/* Sent when a download has been resumed. If a download failed with an
 * error, the -userInfo dictionary of the error will contain an
 * NSURLSessionDownloadTaskResumeData key, whose value is the resume
 * data.
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
    NSLog(@"%s-----fileOffset:%lld,---expectedTotalBytes:%lld",__func__,fileOffset,expectedTotalBytes);
}

NSURLConnection断点下载

#pragma mark - 断点下载
- (IBAction)pause:(UIButton *)sender {
    [sender setSelected:!sender.selected];
    if (sender.selected) {//继续下载
        NSURL *url = [NSURL URLWithString:@"http://127.0.0.1:8080/MJServer/resources/videos/iPhoneSimulator6.1.sdk.zip"];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        //设置Range
        [request setValue:[NSString stringWithFormat:@"bytes=%lld-",self.currentDataLength] forHTTPHeaderField:@"Range"];
        NSLog(@"%@",[NSString stringWithFormat:@"bytes=%lld-",self.currentDataLength]);
        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];

    }else{//暂停下载
        [self.connection cancel];
        self.connection = nil;
    }
}
#pragma mark - NSURLConnectionDataDelegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    self.response = (NSHTTPURLResponse*)response;
    if (self.currentDataLength) {//断点之后的新请求,无需执行以下代码
        return;
    }
    //创建一个和预期下载文件一样大小的文件到沙盒--以便多线程断点下载,的线程分工;----单线程断点下载只需创建一个空文件
    NSString *filePath = HSCachePath([connection.currentRequest.URL lastPathComponent]);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager createFileAtPath:filePath contents:nil attributes:nil];
    //创建文件handle
    self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
    self.totalDataLength = response.expectedContentLength;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    self.currentDataLength += data.length;
//    NSDictionary *dict = [self.response allHeaderFields];
//    NSString *length = dict[@"Content-Length"];//获取预期长度
//    NSString *length = self.response.expectedContentLength;
        [self.circularProgressView setProgress:self.currentDataLength*1.0/self.totalDataLength];
    [self.fileHandle seekToEndOfFile];
    [self.fileHandle writeData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    [self.fileHandle closeFile];
    self.currentDataLength =0;

}
作者:u011018979 发表于2017/7/10 11:48:25 原文链接
阅读:20 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>