android使用http协议上传文件

在Android的客户端编程中(特别是SNS类型的客户端),经常需要实现注册功能Activity,要用户输入用户名,密码,邮箱,照片后注册。但这时就有一个问题,在HTML中用form表单就能实现如上的注册表单,需要的信息会自动封装为完整的HTTP协议,但在Android中如何把这些参数和需要上传的文件封装为HTTP协议呢?

我们可以先做个试验,看一下form表单到底封装了什么样的信息。

第一步:编写一个Servlet,把接收到的HTTP信息保存在一个文件中,代码如下:

publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)

throwsServletException,IOException{

//获取输入流,是HTTP协议中的实体内容

ServletInputStreamsis=request.getInputStream();

//缓冲区

bytebuffer[]=newbyte[1024];

FileOutputStreamfos=newFileOutputStream("d:\\file.log");

intlen=sis.read(buffer,0,1024);

//把流里的信息循环读入到file.log文件中

while(len!=-1)

{

fos.write(buffer,0,len);

len=sis.readLine(buffer,0,1024);

}

fos.close();

sis.close();

}

第二步:实现如下一个表单页面,详细的代码如下:

<formaction="servlet/ReceiveFile"method="post"enctype="multipart/form-data">

第一个参数<inputtype="text"name="name1"/><br/>

第二个参数<inputtype="text"name="name2"/><br/>

第一个上传的文件<inputtype="file"name="file1"/><br/>

第二个上传的文件<inputtype="file"name="file2"/><br/>

<inputtype="submit"value="提交">

</form>

注意了,由于要上传附件,所以一定要设置enctype为multipart/form-data,才可以实现附件的上传。

第三步:填写完信息后按“提交”按钮后,在D盘下查找file.log文件用记事本打开,数据如下:

—————————–7d92221b604bc

Content-Disposition:form-data;name=”name1″

hello

—————————–7d92221b604bc

Content-Disposition:form-data;name=”name2″

world

—————————–7d92221b604bc

Content-Disposition:form-data;name=”file1″;filename=”C:\2.GIF”

Content-Type:image/gif

GIF89a

€€€€€€€€€€€€览?3f3333f333ff3fffff?檉櫃櫶??蘤虣烫?3f3333f3??3333333f33?3?33f3f33ff3f?f?f33?3檉3櫃3櫶3?33?3蘤3虣3烫3?3333f3??ff3fff檉蘤f3f33f3ff3檉3蘤3ffff3fffff檉f蘤fff?f檉f櫃f櫶f?ff?f蘤f虣f烫f?ff3fff檉蘤3f櫃虣??3?f?櫃3虣3檉檉3檉f檉櫃f虣f櫃櫃3櫃f櫃櫃櫶櫃櫶櫶3櫶f櫶櫃烫櫶??3?f?櫃虣3f櫶烫??3?f?櫶3烫3蘤蘤3蘤f蘤櫶f烫f虣虣3虣f虣櫶櫶虣烫烫3烫f烫櫶烫烫??3?f?櫶烫3f??3333f3?3?3ff3fff?f?f?檉櫃櫶??蘤虣烫?3f??!?,

e??羵Q鸚M!C囑lH馉脝远5荑p釩?3R?R愣?MV39V5?谈re琷?试3??qn?薵Q燚c?獖i郸EW艗赥戟j;

—————————–7d92221b604bc

Content-Disposition:form-data;name=”file2″;filename=”C:\2.txt”

Content-Type:text/plain

helloeveryone!!!

—————————–7d92221b604bc–

从表单源码可知,表单上传的数据有4个:参数name1和name2,文件file1和file2

首先从file.log观察两个参数name1和name2的情况。这时候使用UltraEdit打开file.log(因为有些字符在记事本里显示不出来,所以要用16进制编辑器)

结合16进制数据和记事本显示的数据可知上传参数部分的格式规律:

1.第一行是“—————————–7d92221b604bc”作为分隔符,然后是“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

2.第二行

(1)首先是HTTP中的扩展头部分“Content-Disposition:form-data;”,表示上传的是表单数据。

(2)“name=”name1″”参数的名称。

(3)“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

3.第三行:“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

4.第四行:参数的值,最后是“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

由观察可得,表单上传的每个参数都是按照以上1—4的格式构造HTTP协议中的参数部分。

结合16进制数据和记事本显示的数据可知上传文件部分的格式规律:

1.第一行是“—————————–7d92221b604bc”作为分隔符,然后是“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

2.第二行:

a)首先是HTTP中的扩展头部分“Content-Disposition:form-data;”,表示上传的是表单数据。

b)“name=”file2″;”参数的名称。

c)“filename=”C:\2.txt””参数的值。

d)“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

3.第三行:HTTP中的实体头部分“Content-Type:text/plain”:表示所接收到得实体内容的文件格式。计算机的应用中有多种多种通用的文件格式,人们为每种通用格式都定义了一个名称,称为MIME,MIME的英文全称是”MultipurposeInternetMailExtensions”(多功能Internet邮件扩充服务)

4.第四行:“\r\n”(即16进制编辑器显示的0D0A)回车换行符。

5.第五行开始:上传的内容的二进制数。

6.最后是结束标志“—————————–7d92221b604bc–”,注意:这个结束标志和分隔符的区别是最后多了“–”部分。

但现在还有一个问题,就是分隔符“—————————–7d92221b604bc”是怎么确定的呢?是不是一定要“7d92221b604bc”这串数字?

我们以前的分析只是观察了HTTP请求的实体部分,可以借用工具观察完整的HTTP请求看一看有没有什么线索?

在IE下用HttpWatch,在Firefox下用Httpfox这个插件,可以实现网页数据的抓包,从图4可看出,原来在Content-Type部分指定了分隔符所用的字符串。

根据以上总结的注册表单中的参数传递和文件上传的规律,我们可以能写出Android中实现一个用户注册功能(包括个人信息填写和上传图片部分)的工具类,

首先,要有一个javaBean类FormFile封装文件的信息:

publicclassFormFile{

/*上传文件的数据*/

privatebyte[]data;

/*文件名称*/

privateStringfilname;

/*表单字段名称*/

privateStringformname;

/*内容类型*/

privateStringcontentType="application/octet-stream";//需要查阅相关的资料

publicFormFile(Stringfilname,byte[]data,Stringformname,StringcontentType){

this.data=data;

this.filname=filname;

this.formname=formname;

if(contentType!=null)this.contentType=contentType;

}

publicbyte[]getData(){

returndata;

}

publicvoidsetData(byte[]data){

this.data=data;

}

publicStringgetFilname(){

returnfilname;

}

publicvoidsetFilname(Stringfilname){

this.filname=filname;

}

publicStringgetFormname(){

returnformname;

}

publicvoidsetFormname(Stringformname){

this.formname=formname;

}

publicStringgetContentType(){

returncontentType;

}

publicvoidsetContentType(StringcontentType){

this.contentType=contentType;

}

}

实现文件上传的代码如下:

/**

*直接通过HTTP协议提交数据到服务器,实现表单提交功能

*@paramactionUrl上传路径

*@paramparams请求参数key为参数名,value为参数值

*@paramfile上传文件

*/

publicstaticStringpost(StringactionUrl,Map<String,String>params,FormFile[]files){

try{

StringBOUNDARY=“———7d4a6d158c9″;//数据分隔线

StringMULTIPART_FORM_DATA=“multipart/form-data”;

URLurl=newURL(actionUrl);

HttpURLConnectionconn=(HttpURLConnection)url.openConnection();

conn.setDoInput(true);//允许输入

conn.setDoOutput(true);//允许输出

conn.setUseCaches(false);//不使用Cache

conn.setRequestMethod(”POST”);

conn.setRequestProperty(”Connection”,“Keep-Alive”);

conn.setRequestProperty(”Charset”,“UTF-8″);

conn.setRequestProperty(”Content-Type”,MULTIPART_FORM_DATA+“;boundary=”+BOUNDARY);

StringBuildersb=newStringBuilder();

//上传的表单参数部分,格式请参考文章

for(Map.Entry<String,String>entry:params.entrySet()){//构建表单字段内容

sb.append(”–”);

sb.append(BOUNDARY);

sb.append(”\r\n”);

sb.append(”Content-Disposition:form-data;name=\”"+entry.getKey()+“\”\r\n\r\n”);

sb.append(entry.getValue());

sb.append(”\r\n”);

}

DataOutputStreamoutStream=newDataOutputStream(conn.getOutputStream());

outStream.write(sb.toString().getBytes());//发送表单字段数据

//上传的文件部分,格式请参考文章

for(FormFilefile:files){

StringBuildersplit=newStringBuilder();

split.append(”–”);

split.append(BOUNDARY);

split.append(”\r\n”);

split.append(”Content-Disposition:form-data;name=\”"+file.getFormname()+”\”;filename=\”"+file.getFilname()+“\”\r\n”);

split.append(”Content-Type:“+file.getContentType()+”\r\n\r\n”);

outStream.write(split.toString().getBytes());

outStream.write(file.getData(),0,file.getData().length);

outStream.write(”\r\n”.getBytes());

}

byte[]end_data=(”–”+BOUNDARY+“–\r\n”).getBytes();//数据结束标志

outStream.write(end_data);

outStream.flush();

intcah=conn.getResponseCode();

if(cah!=200)thrownewRuntimeException(”请求url失败”);

InputStreamis=conn.getInputStream();

intch;

StringBuilderb=newStringBuilder();

while((ch=is.read())!=-1){

b.append((char)ch);

}

outStream.close();

conn.disconnect();

returnb.toString();

}catch(Exceptione){

thrownewRuntimeException(e);

}

}

出处:http://blog.csdn.net

相关推荐