zoukankan      html  css  js  c++  java
  • ios 文件上传, post数据

    转自:http://www.maxiaoguo.com/clothes/267.html

    一、文件下载

    获取资源文件大小有两张方式

    1、

    HTTP HEAD方法
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeout];
    request.HTTPMethod = @"HEAD";
    [NSURLConnection sendAsynchronousRequest:request queue:self.myQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSLog(@"%@", response);
        NSLog(@"---------------");
        NSLog(@"%@", data);
    }];
    执行測试代码能够发现。HEAD方法仅仅是返回资源信息,而不会返回数据体
    应用场景:
    获取资源Mimetype
    获取资源文件大小。用于端点续传或多线程下载
    2

    使用块代码获取网络资源大小的方法
    - (void)fileSizeWithURL:(NSURL *)url completion:(void (^)(long long contentLength))completion
    {
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeout];
        request.HTTPMethod = @"HEAD"; 
        NSURLResponse *response = nil;
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
        
        completion(response.expectedContentLength);
    }

    确定每次下载数据包的伪代码实现

    - (void)downloadFileWithURL:(NSURL *)url
    {
        [self fileSizeWithURL:url completion:^(long long contentLength) {
            NSLog(@"文件总大小:%lld", contentLength);        
            // 依据大小下载文件
                   while (contentLength > kDownloadBytes) {
                NSLog(@"每次下载长度:%lld", (long long)kDownloadBytes);
                contentLength -= kDownloadBytes;
            }
            NSLog(@"最后下载字节数:%lld", contentLength);
        }];
    }

    HTTP Range的演示样例
    通过设置Range能够指定每次从网路下载数据包的大小
    Range演示样例
    bytes=0-499 从0到499的头500个字节
    bytes=500-999 从500到999的第二个500字节
    bytes=500- 从500字节以后的全部字节
    bytes=-500 最后500个字节
    bytes=500-599,800-899 同一时候指定几个范围
    Range小结
    - 用于分隔
    前面的数字表示起始字节数
    后面的数组表示截止字节数,没有表示到末尾
    , 用于分组,能够一次指定多个Range。只是非常少用

    分段Range代码实现
    long long fromBytes = 0;
    long long toBytes = 0;
    while (contentLength > kDownloadBytes) {
        toBytes = fromBytes + kDownloadBytes - 1;
        NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", fromBytes, toBytes];
        NSLog(@"range %@", range);
        fromBytes += kDownloadBytes;
        contentLength -= kDownloadBytes;
    }
    fromBytes = fromBytes + contentLength - 1;
    NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", fromBytes, toBytes];
    NSLog(@"range %@", range);
    

    分段下载文件
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeout];
    NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", from, end];
    [request setValue:range forHTTPHeaderField:@"Range"];
    
    NSURLResponse *response = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
        
    NSLog(@"%@-%@-%ld", range, response, (unsigned long)data.length);
    提示:
    假设GET包括Range请求头。响应会以状态码206(PartialContent)返回而不是200(OK)

    将数据写入文件
    // 打开缓存文件
    NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.cachePath];
    // 假设文件不存在。直接写入数据
    if (!fp) {
        [data writeToFile:self.cachePath atomically:YES];
    } else {
        // 移动到文件末尾
        [fp seekToEndOfFile];
        // 将数据文件追加到文件末尾
        [fp writeData:data];
        // 关闭文件句柄
        [fp closeFile];
    }

    检查文件大小
    // 推断文件是否存在
    if ([[NSFileManager defaultManager] fileExistsAtPath:self.cachePath]) {
        NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cachePath error:NULL];
        return [dict[NSFileSize] longLongValue];
    } else {
        return 0;
    }
    
    提示:因为数据是追加的。为了避免反复从网络下载文件,在下载之前
    推断缓存路径中文件是否已经存在
    假设存在检查文件大小
    假设文件大小与网络资源大小一致。则不再下载

    所有代码例如以下

    //
    //  MJViewController.m
    //  01.文件下载
    //
    //  Created by apple on 14-4-29.
    //  Copyright (c) 2014年 itcast. All rights reserved.
    //
    
    #import "MJViewController.h"
    #import "FileDownload.h"
    
    @interface MJViewController ()
    @property (nonatomic, strong) FileDownload *download;
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @end
    
    @implementation MJViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.download = [[FileDownload alloc] init];
        [self.download downloadFileWithURL:[NSURL URLWithString:@"http://localhost/itcast/images/head4.png"] completion:^(UIImage *image) {
            
            self.imageView.image = image;
        }];
    }
    
    @end

    //
    //  FileDownload.m
    //  01.文件下载
    //
    //  Created by apple on 14-4-29.
    //  Copyright (c) 2014年 itcast. All rights reserved.
    //
    
    #import "FileDownload.h"
    #import "NSString+Password.h"
    
    #define kTimeOut        2.0f
    // 每次下载的字节数
    #define kBytesPerTimes  20250
    
    @interface FileDownload()
    @property (nonatomic, strong) NSString *cacheFile;
    @property (nonatomic, strong) UIImage *cacheImage;
    @end
    
    @implementation FileDownload
    /**
     为了保证开发的简单,全部方法都不使用多线程,全部的注意力都保持在文件下载上
     
     在开发中假设碰到比較绕的计算问题时,建议:
     1> 測试数据不要太大
     2> 測试数据的数值变化,可以用笔算计算出准确的数值
     3> 编写代码对比測试
    
     */
    //- (NSString *)cacheFile
    //{
    //    if (!_cacheFile) {
    //        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    //        _cacheFile = [cacheDir stringByAppendingPathComponent:@"123.png"];
    //    }
    //    return _cacheFile;
    //}
    - (UIImage *)cacheImage
    {
        if (!_cacheImage) {
            _cacheImage = [UIImage imageWithContentsOfFile:self.cacheFile];
        }
        return _cacheImage;
    }
    
    - (void)setCacheFile:(NSString *)urlStr
    {
        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
        urlStr = [urlStr MD5];
        
        _cacheFile = [cacheDir stringByAppendingPathComponent:urlStr];
    }
    
    - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion
    {
        // GCD中的串行队列异步方法
        dispatch_queue_t q = dispatch_queue_create("cn.itcast.download", DISPATCH_QUEUE_SERIAL);
        
        dispatch_async(q, ^{
            NSLog(@"%@", [NSThread currentThread]);
            
            // 把对URL进行MD5加密之后的结果当成文件名称
            self.cacheFile = [url absoluteString];
            
            // 1. 从网络下载文件,须要知道这个文件的大小
            long long fileSize = [self fileSizeWithURL:url];
            // 计算本地缓存文件大小
            long long cacheFileSize = [self localFileSize];
            
            if (cacheFileSize == fileSize) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completion(self.cacheImage);
                });
                NSLog(@"文件已经存在");
                return;
            }
            
            // 2. 确定每一个数据包的大小
            long long fromB = 0;
            long long toB = 0;
            // 计算起始和结束的字节数
            while (fileSize > kBytesPerTimes) {
                // 20480 + 20480
                //
                toB = fromB + kBytesPerTimes - 1;
                
                // 3. 分段下载文件
                [self downloadDataWithURL:url fromB:fromB toB:toB];
                
                fileSize -= kBytesPerTimes;
                fromB += kBytesPerTimes;
            }
            [self downloadDataWithURL:url fromB:fromB toB:fromB + fileSize - 1];
    
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(self.cacheImage);
            });        
        });
    }
    
    #pragma mark 下载指定字节范围的数据包
    /**
     NSURLRequestUseProtocolCachePolicy = 0,        // 默认的缓存策略,内存缓存
     
     NSURLRequestReloadIgnoringLocalCacheData = 1,  // 忽略本地的内存缓存
     NSURLRequestReloadIgnoringCacheData
     */
    - (void)downloadDataWithURL:(NSURL *)url fromB:(long long)fromB toB:(long long)toB
    {
        NSLog(@"数据包:%@", [NSThread currentThread]);
        
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeOut];
        
        // 指定请求中所要GET的字节范围
        NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld", fromB, toB];
        [request setValue:range forHTTPHeaderField:@"Range"];
        NSLog(@"%@", range);
        
        NSURLResponse *response = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
        
        // 写入文件,覆盖文件不会追加
    //    [data writeToFile:@"/Users/aplle/Desktop/1.png" atomically:YES];
        [self appendData:data];
        
        NSLog(@"%@", response);
    }
    
    #pragma mark - 读取本地缓存文件大小
    - (long long)localFileSize
    {
        // 读取本地文件信息
        NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cacheFile error:NULL];
        NSLog(@"%lld", [dict[NSFileSize] longLongValue]);
        
        return [dict[NSFileSize] longLongValue];
    }
    
    #pragma mark - 追加数据到文件
    - (void)appendData:(NSData *)data
    {
        // 推断文件是否存在
        NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.cacheFile];
        // 假设文件不存在创建文件
        if (!fp) {
            [data writeToFile:self.cacheFile atomically:YES];
        } else {
            // 假设文件已经存在追加文件
            // 1> 移动到文件末尾
            [fp seekToEndOfFile];
            // 2> 追加数据
            [fp writeData:data];
            // 3> 写入文件
            [fp closeFile];
        }
    }
    
    #pragma mark - 获取网络文件大小
    - (long long)fileSizeWithURL:(NSURL *)url
    {
        // 默认是GET
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeOut];
        
        // HEAD 头,仅仅是返回文件资源的信息,不返回详细是数据
        // 假设要获取资源的MIMEType,也必须用HEAD,否则,数据会被反复下载两次
        request.HTTPMethod = @"HEAD";
    
        // 使用同步方法获取文件大小
        NSURLResponse *response = nil;
        
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
        
        // expectedContentLength文件在网络上的大小
        NSLog(@"%lld", response.expectedContentLength);
        
        return response.expectedContentLength;
    }
    
    @end
    


    二、文件上传

    代码例如以下

    //
    //  MJViewController.m
    //  02.Post上传
    //
    //  Created by apple on 14-4-29.
    //  Copyright (c) 2014年 itcast. All rights reserved.
    //
    
    #import "MJViewController.h"
    #import "UploadFile.h"
    
    @interface MJViewController ()
    
    @end
    
    @implementation MJViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        UploadFile *upload = [[UploadFile alloc] init];
        
        NSString *urlString = @"http://localhost/upload.php";
        
        NSString *path = [[NSBundle mainBundle] pathForResource:@"头像1.png" ofType:nil];
        NSData *data = [NSData dataWithContentsOfFile:path];
        
        [upload uploadFileWithURL:[NSURL URLWithString:urlString] data:data];
    }
    
    @end
    

    //
    //  UploadFile.m
    //  02.Post上传
    //
    //  Created by apple on 14-4-29.
    //  Copyright (c) 2014年 itcast. All rights reserved.
    //
    
    #import "UploadFile.h"
    
    @implementation UploadFile
    // 拼接字符串
    static NSString *boundaryStr = @"--";   // 分隔字符串
    static NSString *randomIDStr;           // 本次上传标示字符串
    static NSString *uploadID;              // 上传(php)脚本中,接收文件字段
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            randomIDStr = @"itcast";
            uploadID = @"uploadFile";
        }
        return self;
    }
    
    #pragma mark - 私有方法
    - (NSString *)topStringWithMimeType:(NSString *)mimeType uploadFile:(NSString *)uploadFile
    {
        NSMutableString *strM = [NSMutableString string];
        
        [strM appendFormat:@"%@%@
    ", boundaryStr, randomIDStr];
        [strM appendFormat:@"Content-Disposition: form-data; name="%@"; filename="%@"
    ", uploadID, uploadFile];
        [strM appendFormat:@"Content-Type: %@
    
    ", mimeType];
        
        NSLog(@"%@", strM);
        return [strM copy];
    }
    
    - (NSString *)bottomString
    {
        NSMutableString *strM = [NSMutableString string];
        
        [strM appendFormat:@"%@%@
    ", boundaryStr, randomIDStr];
        [strM appendString:@"Content-Disposition: form-data; name="submit"
    
    "];
        [strM appendString:@"Submit
    "];
        [strM appendFormat:@"%@%@--
    ", boundaryStr, randomIDStr];
        
        NSLog(@"%@", strM);
        return [strM copy];
    }
    
    #pragma mark - 上传文件
    - (void)uploadFileWithURL:(NSURL *)url data:(NSData *)data
    {
        // 1> 数据体
        NSString *topStr = [self topStringWithMimeType:@"image/png" uploadFile:@"头像1.png"];
        NSString *bottomStr = [self bottomString];
        
        NSMutableData *dataM = [NSMutableData data];
        [dataM appendData:[topStr dataUsingEncoding:NSUTF8StringEncoding]];
        [dataM appendData:data];
        [dataM appendData:[bottomStr dataUsingEncoding:NSUTF8StringEncoding]];
        
        // 1. Request
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:2.0f];
        
        // dataM出了作用域就会被释放,因此不用copy
        request.HTTPBody = dataM;
        
        // 2> 设置Request的头属性
        request.HTTPMethod = @"POST";
        
        // 3> 设置Content-Length
        NSString *strLength = [NSString stringWithFormat:@"%ld", (long)dataM.length];
        [request setValue:strLength forHTTPHeaderField:@"Content-Length"];
        
        // 4> 设置Content-Type
        NSString *strContentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", randomIDStr];
        [request setValue:strContentType forHTTPHeaderField:@"Content-Type"];
        
        // 3> 连接server发送请求
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            
            NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@", result);
        }];
    }
    
    
    
    @end
    



  • 相关阅读:
    OleDbCommand 的用法
    递归求阶乘
    C#重写窗体的方法
    HDU 5229 ZCC loves strings 博弈
    HDU 5228 ZCC loves straight flush 暴力
    POJ 1330 Nearest Common Ancestors LCA
    HDU 5234 Happy birthday 01背包
    HDU 5233 Gunner II 离散化
    fast-IO
    HDU 5265 pog loves szh II 二分
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6923683.html
Copyright © 2011-2022 走看看