您的位置:首页 > 移动开发 > IOS开发

IOS上传图片、视频、文件原理

2013-12-08 10:56 501 查看
其实不应当归类到iOS当中,因为实际上是属于RFC 1867RFC 1341一类的东西。他们规定:这种需要执行 多部分POST(multipart
POST)标准的情形,需要把图片啊视频啊等数据设置到HTTP【正文】当中,也就是要把表单项数据(也就是参数及其值)跟二进制文件数据相结合。

其中最让人望而生畏也最容易搞不懂的怕就是“边界字符串”了,其实就是任意内容的字符串(但是要两个横线开头),只要字符串的内容不与正文的其他部分发生冲突就行啦,比如:

NSString *boundaryStr=[[NSStringalloc]initWithFormat:@"--WriteByShareHoney"];
参见:http://www.ietf.org/rfc/rfc1341.txt

The  encapsulation  boundary   is defined   as  a  line  consisting  entirely  of  two  hyphen characters ("-", decimal code 45) followed by  the  boundary parameter value from the Content-Type header field.


【正文】需要由“边界字符串”封装,所以第一行就应该出现boundaryStr,而且之前【必须】要有换行。

这也要在【HTTPHeader】中对应的设置,如下:

//设置HTTPHeader
NSString *content=[[NSString alloc]initWithFormat:@"multipart/form-data;boundary=%@",boundaryStr];

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

即:Content-type: multipart/form-data, boundary=AaB03x 

这直接指定了http post请求的编码方式为multipart/form-data;

boundary=AaB03x则指AaB03x为“边界字符串”。
参考自http://borissun.iteye.com/blog/1338991

往下就好说了,把不同的字段用“边界字符串”分开:

//“边界字符串 单独占一行

--AaB03x    

//字段 field1。 content-disposition 个人理解为 内容特性 的意思。

content-disposition: form-data; name="field1"    

//换行2次 空行,必须的

//字段的值   单独占一行

Hello Boris!    
//“边界字符串 单独占一行
--AaB03x    
//字段 name 和 filename
content-disposition: form-data; name="pic"; filename="boris.png"    
//内容类型 与filename字段相对应
Content-Type: image/png    
//换行2次 空行,必须的

    

 <89504e47 ... 图片的二进制内容...>

 //“边界字符串 单独占一行

 --AaB03x 

 

 

这样看可能还有些蒙,其实就是合并几个字段:

Content-type: multipart/form-data, boundary=...    

content-disposition: form-data; name=...; filename=...    

Content-Type: ...   

参见代码吧:

//分界线的标识符,也就是“边界字符串”

NSString *TWITTERFON_FORM_BOUNDARY = @"AaB03x";

NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:_urlStr]

                                                       cachePolicy:NSURLRequestReloadIgnoringLocalCacheData

                                                   timeoutInterval:10];

//分界线添加"--"【前缀】,【重要】

NSString *MPboundary=[[NSString alloc]initWithFormat:@"--%@",TWITTERFON_FORM_BOUNDARY];

//结束符就是分界线

NSString *endMPboundary=[[NSString alloc]initWithFormat:@"%@--",MPboundary];

NSData *data = nil;

if (UIImagePNGRepresentation(image)) {

     data = UIImagePNGRepresentation(image);

}

else

{

    data = UIImageJPEGRepresentation(image, 1.0);

}

//http body的字符串

NSMutableString *body=[[NSMutableString alloc]init];

//遍历参数集合,将键值对合并到body(正文)中去

NSArray *keys= [postParems allKeys];

for(int i=0;i<[keys count];i++)

{

    NSString *key=[keys objectAtIndex:i];

    //如果key不是pic,说明value是字符类型,比如name:Boris

    if(![key isEqualToString:@"pic"])

    {

        //添加分界线,【换行】

        [body appendFormat:@"%@\r\n",MPboundary];

        //添加字段名称,【换2行】

        [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];

        //添加字段的值

        [body appendFormat:@"%@\r\n",[postParems objectForKey:key]];

    }

}

////添加分界线,换行

[body appendFormat:@"%@\r\n",MPboundary];

//声明pic字段,文件名为boris.png

[body appendFormat:@"Content-Disposition: form-data; name=\"uploadedfile\"; filename=\"boris.png\"\r\n"];

//声明上传文件的格式

if (UIImagePNGRepresentation(image))

{

//【换2行】

    [body appendFormat:@"Content-Type: image/png\r\n\r\n"];

}

else

{

    [body appendFormat:@"Content-Type: image/jpg\r\n\r\n"];

}

//声明结束符,主意有【换行】

NSString *end=[[NSString alloc]initWithFormat:@"\r\n%@",endMPboundary];

//声明myRequestData,用来放入http body

NSMutableData *myRequestData=[NSMutableData data];

//将body字符串转化为【UTF8格式的二进制】

[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];

//将image的data加入

[myRequestData appendData:data];

//加入结束符--AaB03x--  【正文】封装完毕。

[myRequestData appendData:[end dataUsingEncoding:NSUTF8StringEncoding]];

//设置【HTTPHeader】中Content-Type的值

NSString *content=[[NSString alloc]initWithFormat:@"multipart/form-data; boundary=%@",TWITTERFON_FORM_BOUNDARY];

//设置HTTPHeader

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

//设置Content-Length

[request setValue:[NSString stringWithFormat:@"%d", [myRequestData length]] forHTTPHeaderField:@"Content-Length"];

//设置【http body】

[request setHTTPBody:myRequestData];

//设置【http method】

[request setHTTPMethod:@"POST"];

[NSURLConnection connectionWithRequest:request delegate:self];

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

另:

如果上传的文件很大,数10m甚至上100m,建议使用NSInputStream从文件中读取,而不是用NSData从内存中获取数据,不然怕是内存吃紧,从而app也就不稳定了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iOS 编码 网络