ios开发网络学习五:输出流以及文件上传

一:输出流

#import "ViewController.h"

@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;

@property (nonatomic, assign) NSInteger totalSize;
@property (nonatomic, assign) NSInteger currentSize;
/** 沙盒路径 */
@property (nonatomic, strong) NSString *fullPath;
/** 连接对象 */
@property (nonatomic, strong) NSURLConnection *connect;
/** 输出流*/
@property (nonatomic, strong) NSOutputStream *stream;
@end

@implementation ViewController


- (IBAction)startBtnClick:(id)sender {
    [self download];
}
- (IBAction)cancelBtnClick:(id)sender {
    [self.connect cancel];
}
- (IBAction)goOnBtnClick:(id)sender {
    [self download];
}

//内存飙升
-(void)download
{
    //1.url
    // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"];
    
    NSURL *url = [NSURL URLWithString:@"http://www.33lc.com/article/UploadPic/2012-10/2012102514201759594.jpg"];
    
    //2.创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //设置请求头信息,告诉服务器值请求一部分数据range
    /*
     bytes=0-100 
     bytes=-100
     bytes=0- 请求100之后的所有数据
     */
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
    [request setValue:range forHTTPHeaderField:@"Range"];
    NSLog(@"+++++++%@",range);
    
    //3.发送请求
    NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    self.connect = connect;
}

#pragma mark ----------------------
#pragma mark NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"didReceiveResponse");
    
    //1.得到文件的总大小(本次请求的文件数据的总大小 != 文件的总大小)
    // self.totalSize = response.expectedContentLength + self.currentSize;
    
    if (self.currentSize >0) {
        return;
    }
    
    self.totalSize = response.expectedContentLength;
    
    //2.写数据到沙盒中
    self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.jpg"];
    
    NSLog(@"%@",self.fullPath);
    //3.创建输出流
//    NSOutputStream
//    NSInputStream
    /*
     第一个参数:文件的路径
     第二个参数:YES 追加
     特点:如果该输出流指向的地址没有文件,那么会自动创建一个空的文件
     */
    NSOutputStream *stream = [[NSOutputStream alloc]initToFileAtPath:self.fullPath append:YES];
    
    //打开输出流
    [stream open];
    self.stream = stream;
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //写数据
    [self.stream write:data.bytes maxLength:data.length];
    
    //3.获得进度
    self.currentSize += data.length;
    
    //进度=已经下载/文件的总大小
    NSLog(@"%f",1.0 *  self.currentSize/self.totalSize);
    self.progressView.progress = 1.0 *  self.currentSize/self.totalSize;
    //NSLog(@"%@",self.fullPath);
}

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

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    
    //关闭流
    [self.stream close];
    self.stream = nil;
    
    NSLog(@"connectionDidFinishLoading");
    NSLog(@"%@",self.fullPath);
}
@end

#####7.0  输出流

(1)使用输出流也可以实现和NSFileHandle相同的功能

(2)如何使用

```objc

    //1.创建一个数据输出流

    /*

     第一个参数:二进制的流数据要写入到哪里

     第二个参数:采用什么样的方式写入流数据,如果YES则表示追加,如果是NO则表示覆盖

     */

    NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:fullPath append:YES];

    //只要调用了该方法就会往文件中写数据

    //如果文件不存在,那么会自动的创建一个

    [stream open];

    self.stream = stream;

    //2.当接收到数据的时候写数据

    //使用输出流写数据

    /*

     第一个参数:要写入的二进制数据

     第二个参数:要写入的数据的大小

     */

    [self.stream write:data.bytes maxLength:data.length];

    //3.当文件下载完毕的时候关闭输出流

    //关闭输出流

    [self.stream close];

    self.stream = nil;

```

 二:文件上传

//文件上传步骤

/**
 *    1:NSURLConnection的post请求:1:需要初始化url确定请求路径,设置可变请求对象NSMutableURLRequest,设置请求方式post,设置请求头,设置请求体,发送异步请求文件上传
 */





/*
 1.设置请求头 :boundary为分隔符
 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx
 2.按照固定的格式拼接请求体的数据
 
 ------WebKitFormBoundaryjv0UfA04ED44AhWx
 Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
 Content-Type: image/png
 
 
 ------WebKitFormBoundaryjv0UfA04ED44AhWx
 Content-Disposition: form-data; name="username"
 
 123456
 ------WebKitFormBoundaryjv0UfA04ED44AhWx--
 
 */
//拼接请求体的数据格式
/*
 拼接请求体
 分隔符:----WebKitFormBoundaryjv0UfA04ED44AhWx
 1)文件参数
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
     Content-Type: image/png(MIMEType:大类型/小类型)
     空行
     文件参数
 2)非文件参数
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     123456
 3)结尾标识
    --分隔符--
 */
#import "ViewController.h"

#define Kboundary @"----WebKitFormBoundaryjv0UfA04ED44AhWx"
#define KNewLine [@"
" dataUsingEncoding:NSUTF8StringEncoding]

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self upload];
}

-(void)upload
{
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    
    //2.创建可变的请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //3.设置请求方法
    request.HTTPMethod = @"POST";
    
    //4.设置请求头信息
    //Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
    
    //5.拼接请求体数据
    NSMutableData *fileData = [NSMutableData data];
    //5.1 文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
     Content-Type: image/png(MIMEType:大类型/小类型)
     空行
     文件参数
     */
    //字符串转码:dataUsingEncoding
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //name:file 服务器规定的参数
    //filename:Snip20160225_341.png 文件保存到服务器上面的名称
    //Content-Type:文件的类型
    //其中的代表转义,对双引号进行转义
    [fileData appendData:[@"Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    
    UIImage *image = [UIImage imageNamed:@"Snip20160225_341"];
    
    /**
     *  1:将image转化成data的格式:UIImagePNGRepresentation或是jpeg
     *
     */
    //UIImage --->NSData
    NSData *imageData = UIImagePNGRepresentation(image);
    [fileData appendData:imageData];
    [fileData appendData:KNewLine];
    
    //5.2 非文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     123456
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Disposition: form-data; name="username"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"123456" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //5.3 结尾标识
    /*
     --分隔符--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    //6.设置请求体
    request.HTTPBody = fileData;
    
    //7.发送请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
       
        //8.解析数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
}

@end

#####10.0  文件的上传

- 10.1 文件上传步骤

        (1)确定请求路径

        (2)根据URL创建一个可变的请求对象

        (3)设置请求对象,修改请求方式为POST

        (4)设置请求头,告诉服务器我们将要上传文件(Content-Type)

        (5)设置请求体(在请求体中按照既定的格式拼接要上传的文件参数和非文件参数等数据)

            001 拼接文件参数

            002 拼接非文件参数

            003 添加结尾标记

        (6)使用NSURLConnection sendAsync发送异步请求上传文件

        (7)解析服务器返回的数据

- 10.2 文件上传设置请求体的数据格式

        //请求体拼接格式

        //分隔符:----WebKitFormBoundaryhBDKBUWBHnAgvz9c

        //01.文件参数拼接格式

         --分隔符

         Content-Disposition:参数

         Content-Type:参数

         空行

         文件参数

        //02.非文件拼接参数

         --分隔符

         Content-Disposition:参数

         空行

         非文件的二进制数据

        //03.结尾标识

        --分隔符--

- 10.3 文件上传相关代码

```objc

- (void)upload

{

    //1.确定请求路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];

    //2.创建一个可变的请求对象

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    //3.设置请求方式为POST

    request.HTTPMethod = @"POST";

    //4.设置请求头

    NSString *filed = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary];

    [request setValue:filed forHTTPHeaderField:@"Content-Type"];

    //5.设置请求体

    NSMutableData *data = [NSMutableData data];

    //5.1 文件参数

    /*

     --分隔符

     Content-Disposition:参数

     Content-Type:参数

     空行

     文件参数

     */

    [data appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [data appendData:KnewLine];

    [data appendData:[@"Content-Disposition: form-data; name="file"; filename="test.png"" dataUsingEncoding:NSUTF8StringEncoding]];

    [data appendData:KnewLine];

    [data appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];

    [data appendData:KnewLine];

    [data appendData:KnewLine];

    [data appendData:KnewLine];

    UIImage *image = [UIImage imageNamed:@"test"];

    NSData *imageData = UIImagePNGRepresentation(image);

    [data appendData:imageData];

    [data appendData:KnewLine];

    //5.2 非文件参数

    /*

     --分隔符

     Content-Disposition:参数

     空行

     非文件参数的二进制数据

     */

    [data appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [data appendData:KnewLine];

    [data appendData:[@"Content-Disposition: form-data; name="username"" dataUsingEncoding:NSUTF8StringEncoding]];

    [data appendData:KnewLine];

    [data appendData:KnewLine];

    [data appendData:KnewLine];

    NSData *nameData = [@"wendingding" dataUsingEncoding:NSUTF8StringEncoding];

    [data appendData:nameData];

    [data appendData:KnewLine];

    //5.3 结尾标识

    //--分隔符--

    [data appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [data appendData:KnewLine];

    request.HTTPBody = data;

    //6.发送请求

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

        //7.解析服务器返回的数据

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

    }];

}

```

原文地址:https://www.cnblogs.com/cqb-learner/p/5861758.html