zoukankan      html  css  js  c++  java
  • android使用http协议上传文件

    博客分类:

     

    android使用http协议上传文件

    转载自 http://www.eoeandroid.com/thread-16460-1-1.html

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

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

    Java代码 复制代码 收藏代码
    1. publicvoid doPost(HttpServletRequest request, HttpServletResponse response) 
    2.            throws ServletException, IOException { 
    3.        //获取输入流,是HTTP协议中的实体内容 
    4.        ServletInputStream  sis=request.getInputStream(); 
    5.        //缓冲区 
    6.        byte buffer[]=newbyte[1024]; 
    7.        FileOutputStream fos=new FileOutputStream("d:\\file.log"); 
    8.        int len=sis.read(buffer, 0, 1024); 
    9.        //把流里的信息循环读入到file.log文件中 
    10.        while( len!=-1
    11.        { 
    12.            fos.write(buffer, 0, len); 
    13.            len=sis.readLine(buffer, 0, 1024); 
    14.        } 
    15.        fos.close(); 
    16.        sis.close(); 
    17.     } 
    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();
        }

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

    <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="提交">
    & lt;/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

          €   € €€   €€ € €€€€€览?                                                                                      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进制编辑器)

           结合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协议中的参数部分。

    结合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可看出,原来在Content-Type部分指定了分隔符所用的字符串。
    根据以上总结的注册表单中的参数传递和文件上传的规律,我们可以能写出Android中实现一个用户注册功能(包括个人信息填写和上传图片部分)的工具类,

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

    Java代码 复制代码 收藏代码
    1. publicclass FormFile { 
    2. /* 上传文件的数据 */ 
    3. privatebyte[] 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!=null) this.contentType = contentType; 
    16.  
    17. publicbyte[] getData() { 
    18.   return data; 
    19.  
    20. publicvoid setData(byte[] data) { 
    21.   this.data = data; 
    22.  
    23. public String getFilname() { 
    24.   return filname; 
    25.  
    26. publicvoid setFilname(String filname) { 
    27.   this.filname = filname; 
    28.  
    29. public String getFormname() { 
    30.   return formname; 
    31.  
    32. publicvoid setFormname(String formname) { 
    33.   this.formname = formname; 
    34.  
    35. public String getContentType() { 
    36.   return contentType; 
    37.  
    38. publicvoid setContentType(String contentType) { 
    39.   this.contentType = contentType; 
    40.  
    public class FormFile {
    /* 上传文件的数据 */
    private byte[] data;
    /* 文件名称 */
    private String filname;
    /* 表单字段名称*/
    private String formname;
    /* 内容类型 */
    private String contentType = "application/octet-stream"; //需要查阅相关的资料
    
    public FormFile(String filname, byte[] data, String formname, String contentType) {
      this.data = data;
      this.filname = filname;
      this.formname = formname;
      if(contentType!=null) this.contentType = contentType;
    }
    
    public byte[] getData() {
      return data;
    }
    
    public void setData(byte[] data) {
      this.data = data;
    }
    
    public String getFilname() {
      return filname;
    }
    
    public void setFilname(String filname) {
      this.filname = filname;
    }
    
    public String getFormname() {
      return formname;
    }
    
    public void setFormname(String formname) {
      this.formname = formname;
    }
    
    public String getContentType() {
      return contentType;
    }
    
    public void setContentType(String contentType) {
      this.contentType = contentType;
    }
    
    }

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

    Java代码 复制代码 收藏代码
    1. /**
    2. * 直接通过HTTP协议提交数据到服务器,实现表单提交功能
    3. * @param actionUrl 上传路径
    4. * @param params 请求参数 key为参数名,value为参数值
    5. * @param file 上传文件
    6. */ 
    7. publicstatic 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) thrownew 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.         thrownew RuntimeException(e);   
    64.     }   
    65. }   
  • 相关阅读:
    gulp的使用
    Js中call(),apply()的使用
    HTML中<meta>标签的使用
    字符串及数组常用方法
    css—transform
    《Java设计模式》——适配器模式
    全文检索工具包Lucene以及企业及应用Solr的学习(二)—— solr中edismax用到的Query Function以及java扩展
    全文检索工具包Lucene以及企业及应用Solr的学习(一)
    最近发现服务器发生了一些问题
    TxT读取写入
  • 原文地址:https://www.cnblogs.com/lzhitian/p/2424016.html
Copyright © 2011-2022 走看看