Android下的应用编程——用HTTP协议实现文件上传功能

来源:互联网 发布:乐乎公寓官网投诉电话 编辑:程序博客网 时间:2024/06/06 20:51

【文章标题】Android下的应用编程——用HTTP协议实现文件上传功能

【文章作者】曾健生

【作者邮箱】zengjiansheng1@126.com

【作者QQ】190678908

【作者MSN】zengjiansheng1@hotmail.com

【作者博客】blog.csdn.net/newjueqi

 

 

*******************************************************************************

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

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

 

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

 

    public void doPost(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

 

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

       ServletInputStream  sis=request.getInputStream();

     

       //缓冲区

       byte buffer[]=new byte[1024];

      

       FileOutputStream fos=new FileOutputStream("d://file.log");

      

       int len=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();

      

    }

 

第二步:实现如下图1的的表单页面,生成一个注册表单,提交到Servlet中

             

                                            图1

 

 

 详细的代码如下:

 

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

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

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

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

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

    <input type="submit" value="提交">

</form>

 

注意了,由于要上传附件,所以一定要设置enctypemultipart/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

 

      €   € €€   €€ € €€€€€览?                                                                                     3  f       3  33 3f 3 3 3 f  f3 ff f f f   ? 檉 櫃 櫶 ?   ? 蘤 虣 烫 ?   3 f   3  3 33 f3 ? ? 33 33333f33?3?33f 3f33ff3f?f?f3 3?3檉3櫃3櫶3?3 3?3蘤3虣3烫3?3 333f3??f  f 3f ff 檉 蘤 f3 f33f3ff3檉3蘤3ff ff3fffff檉f蘤ff f?f檉f櫃f櫶f?f f?f蘤f虣f烫f?f f3fff檉蘤   3 f 櫃 虣 ? ?3?f?櫃3虣3檉 檉3檉f檉櫃f虣f櫃 櫃3櫃f櫃櫃櫶櫃櫶 櫶3櫶f櫶櫃烫櫶? ?3?f?櫃虣   3 f 櫶 烫 ? ?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

 

hello everyone!!!

-----------------------------7d92221b604bc--

 

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

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

                                           

                                              图2

 

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

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

2.       第二行

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

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

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

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

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

 

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

 

那么我们再来看上传的文件部分(以第二个上传的文件2.txt为例)图3:

 

                                                                   

                                     图3

 

 

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

 

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

2.       第二行:

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

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

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

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

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

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

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

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

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

 

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

  在IE下用HttpWatch,在Firefox下用Httpfox这个插件,可以实现网页数据的抓包,结果如下图:

 

 

                                                                 图4

从图4可看出,原来在Content-Type部分指定了分隔符所用的字符串。

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

 

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

 

 

 

[java] view plaincopy
  1. public class FormFile {  
  2.     /* 上传文件的数据 */  
  3.     private byte[] data;  
  4.     /* 文件名称 */  
  5.     private String filname;  
  6.     /* 表单字段名称*/  
  7.     private String formname;  
  8.     /* 内容类型 */  
  9.     private String contentType = "application/octet-stream"//需要查阅相关的资料  
  10.       
  11.     public FormFile(String filname, byte[] data, String formname, String contentType) {  
  12.         this.data = data;  
  13.         this.filname = filname;  
  14.         this.formname = formname;  
  15.         if(contentType!=nullthis.contentType = contentType;  
  16.     }  
  17.   
  18.     public byte[] getData() {  
  19.         return data;  
  20.     }  
  21.   
  22.     public void setData(byte[] data) {  
  23.         this.data = data;  
  24.     }  
  25.   
  26.     public String getFilname() {  
  27.         return filname;  
  28.     }  
  29.   
  30.     public void setFilname(String filname) {  
  31.         this.filname = filname;  
  32.     }  
  33.   
  34.     public String getFormname() {  
  35.         return formname;  
  36.     }  
  37.   
  38.     public void setFormname(String formname) {  
  39.         this.formname = formname;  
  40.     }  
  41.   
  42.     public String getContentType() {  
  43.         return contentType;  
  44.     }  
  45.   
  46.     public void setContentType(String contentType) {  
  47.         this.contentType = contentType;  
  48.     }  
  49.       
  50. }  
 

  

 

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

 

 

                                                        

[c-sharp] view plaincopy
  1. /** 
  2.  * 直接通过HTTP协议提交数据到服务器,实现表单提交功能 
  3.  * @param actionUrl 上传路径 
  4.  * @param params 请求参数 key为参数名,value为参数值 
  5.  * @param file 上传文件 
  6.  */  
  7. public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {  
  8.     try {             
  9.         String BOUNDARY = "---------7d4a6d158c9"//数据分隔线  
  10.         String MULTIPART_FORM_DATA = "multipart/form-data";  
  11.           
  12.         URL url = new URL(actionUrl);  
  13.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  14.         conn.setDoInput(true);//允许输入  
  15.         conn.setDoOutput(true);//允许输出  
  16.         conn.setUseCaches(false);//不使用Cache  
  17.         conn.setRequestMethod("POST");            
  18.         conn.setRequestProperty("Connection""Keep-Alive");  
  19.         conn.setRequestProperty("Charset""UTF-8");  
  20.         conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);  
  21.   
  22.         StringBuilder sb = new StringBuilder();  
  23.           
  24.         //上传的表单参数部分,格式请参考文章  
  25.         for (Map.Entry<String, String> entry : params.entrySet()) {//构建表单字段内容  
  26.             sb.append("--");  
  27.             sb.append(BOUNDARY);  
  28.             sb.append("/r/n");  
  29.             sb.append("Content-Disposition: form-data; name=/""+ entry.getKey() + "/"/r/n/r/n");  
  30.             sb.append(entry.getValue());  
  31.             sb.append("/r/n");  
  32.         }  
  33.         DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());  
  34.         outStream.write(sb.toString().getBytes());//发送表单字段数据  
  35.          
  36.         //上传的文件部分,格式请参考文章  
  37.         for(FormFile file : files){  
  38.             StringBuilder split = new StringBuilder();  
  39.             split.append("--");  
  40.             split.append(BOUNDARY);  
  41.             split.append("/r/n");  
  42.             split.append("Content-Disposition: form-data;name=/""+ file.getFormname()+"/";filename=/""+ file.getFilname() + "/"/r/n");  
  43.             split.append("Content-Type: "+ file.getContentType()+"/r/n/r/n");  
  44.             outStream.write(split.toString().getBytes());  
  45.             outStream.write(file.getData(), 0, file.getData().length);  
  46.             outStream.write("/r/n".getBytes());  
  47.         }  
  48.         byte[] end_data = ("--" + BOUNDARY + "--/r/n").getBytes();//数据结束标志           
  49.         outStream.write(end_data);  
  50.         outStream.flush();  
  51.         int cah = conn.getResponseCode();  
  52.         if (cah != 200) throw new RuntimeException("请求url失败");  
  53.         InputStream is = conn.getInputStream();  
  54.         int ch;  
  55.         StringBuilder b = new StringBuilder();  
  56.         while( (ch = is.read()) != -1 ){  
  57.             b.append((char)ch);  
  58.         }  
  59.         outStream.close();  
  60.         conn.disconnect();  
  61.         return b.toString();  
  62.     } catch (Exception e) {  
  63.         throw new RuntimeException(e);  
0 0
原创粉丝点击