`
xixinfei
  • 浏览: 414809 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

 
阅读更多

http://blog.csdn.net/newjueqi/article/details/4777779

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

【文章作者】曾健生

【作者邮箱】zengjiansheng1@126.com

【作者QQ190678908

【作者MSNzengjiansheng1@hotmail.com

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

 

 

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

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

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

 

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

 

    publicvoid doPost(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

 

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

       ServletInputStream  sis=request.getInputStream();

     

       //缓冲区

       byte buffer[]=newbyte[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

 


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

Content-Disposition: form-data; name="file2"; filename="C:/2.txt"

Content-Type: text/plain

 

hello everyone!!!

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

 

       从表单源码可知,表单上传的数据有4个:参数name1name2,文件file1file2

首先从file.log观察两个参数name1name2的情况。这时候使用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)回车换行符。

 

由观察可得,表单上传的每个参数都是按照以上14的格式构造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”:表示所接收到得实体内容的文件格式。计算机的应用中有多种多种通用的文件格式,人们为每种通用格式都定义了一个名称,称为MIMEMIME的英文全称是"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中实现一个用户注册功能(包括个人信息填写和上传图片部分)的工具类,

 

首先,要有一个javaBeanFormFile封装文件的信息:

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;
    }
   
}
实现文件上传的代码如下:

/**
     * 直接通过HTTP协议提交数据到服务器,实现表单提交功能
     * @param actionUrl 上传路径
     * @param params 请求参数 key为参数名,value为参数值
     * @param file 上传文件
     */
    public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {
        try {           
            String BOUNDARY = "---------7d4a6d158c9"; //数据分隔线
            String MULTIPART_FORM_DATA = "multipart/form-data";
           
            URL url = new URL(actionUrl);
            HttpURLConnection conn = (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);

            StringBuilder sb = new StringBuilder();
           
            //上传的表单参数部分,格式请参考文章
            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");
            }
            DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
            outStream.write(sb.toString().getBytes());//发送表单字段数据
          
            //上传的文件部分,格式请参考文章
            for(FormFile file : files){
                StringBuilder split = new StringBuilder();
                 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();
            int cah = conn.getResponseCode();
            if (cah != 200) throw new RuntimeException("请求url失败");
            InputStream is = conn.getInputStream();
            int ch;
            StringBuilder b = new StringBuilder();
            while( (ch = is.read()) != -1 ){
                b.append((char)ch);
            }
            outStream.close();
            conn.disconnect();
            return b.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

 

 

分享到:
评论

相关推荐

    安卓Android源码——-simpl3r-文件上传master.zip

    "simpl3r"是一个专门用于文件上传的项目,其源码提供了详细的实现细节,可以帮助开发者了解如何在Android应用中实现这一功能。下面我们将深入探讨这个项目中的关键知识点。 1. **文件上传基础**: 文件上传是移动...

    安卓Android源码——基于socket通讯的文件续传!.zip

    在安卓(Android)平台上,开发过程中常常涉及到网络通信,尤其是文件传输。..."的项目可能包含一个实现上述逻辑的示例应用,通过分析和学习,开发者可以掌握如何在Android应用中实现实用且高效的文件续传功能。

    安卓Android源码——android拍摄视频并上传到PHP服务器.rar

    这些知识点涵盖了从录制视频到上传到服务器的基本过程,对于理解和实现类似的Android应用具有重要的参考价值。开发者可以通过研究这个示例源码,深入理解Android多媒体和网络编程,提高自己的开发技能。

    安卓Android源码——Android版FTP服务器 SwiFTP源代码.7z

    SwiFTP是由开源社区开发的一款Android上的FTP服务器应用,它实现了基本的FTP服务功能,包括用户登录验证、文件目录浏览、文件上传和下载等。其源代码结构清晰,适合开发者学习和二次开发。 三、SwiFTP关键组件 1. *...

    安卓Android源码——仿飞鸽传书源码.zip

    1. **Android SDK的使用**:如何利用Android提供的API进行网络通信,实现文件上传下载,以及如何处理数据传输的安全性。 2. **即时通讯协议**:可能涉及到TCP/IP或HTTP等网络协议,以及如何实现即时消息的发送和接收...

    Android源码——仿飞鸽传书源码.zip

    【Android源码——仿飞鸽传书源码.zip】是一个包含Android应用程序源代码的压缩文件,旨在帮助开发者理解和实现类似“飞鸽传书”的即时通讯功能。在这个项目中,你可以学习到如何在Android平台上构建一个基本的文件...

    Android 简单FTP上传文件.zip

    本教程将详述如何使用Java编程语言在Android应用中实现简单的FTP文件上传功能。首先,我们需要了解FTP的基本概念,以及在Android环境中如何设置和使用FTP客户端。 FTP工作原理: FTP基于TCP/IP协议,通过建立两个...

    云应用开发 ——Google App Engine & Google Web Toolkit入门指南

    - **10.3.15 手机端界面与功能实现**:实现 Android 端的应用界面和功能。 - **10.3.16 总结**:回顾整个开发过程,总结经验教训。 通过这三个不同的案例,读者不仅可以学到 GWT 和 Google App Engine 的基础知识,...

    安卓Android源码——在远程上传以及下载图片---XFire框架.zip

    总的来说,这个资源包中的内容将帮助开发者理解和实践如何在Android应用中利用XFire框架处理图片的远程上传和下载,提高开发效率,同时确保网络操作的稳定性和用户体验。通过学习和应用这些源码,开发者可以深入理解...

    Android源码——完美高仿的微信源码.zip

    通过深入分析这个“完美高仿的微信源码”,开发者可以了解到一个复杂Android应用的架构设计、功能实现、性能调优等多个层面的知识,这对于提升个人的Android开发技能非常有帮助。然而,需要注意的是,虽然可以直接...

    Android源码——高仿QQ的即时通讯(附带服务端).7z

    高仿QQ的Android应用应该遵循MVP(Model-View-Presenter)或MVVM(Model-View-ViewModel)架构,以保证代码的可维护性和可测试性。Model层处理数据逻辑,Presenter/ViewModel负责业务逻辑,View则专注于用户界面的...

    安卓Android源码——手机通讯集信息,文件,语音呼叫于一体(小鸟版).rar

    3. **文件管理**:文件传输可能涉及文件选择器、文件上传下载功能。Android提供了ContentResolver和ContentProvider接口,用于访问和操作设备上的文件系统。此外,可能还需要使用到Socket编程进行网络文件传输。 4....

    Android源码——仿开心网源代码.zip

    通过分析这个开源项目,我们可以了解到Android应用程序设计的基本原则,以及开心网的一些核心功能的实现方式。 首先,我们要明白Android是一个基于Linux内核的开源操作系统,主要用于移动设备如智能手机和平板电脑...

    android 网络编程 客户端完整代码 socket http

    在Android平台上进行网络编程是开发应用不可或缺的一部分,无论是获取服务器数据、实时通信还是文件传输,都需要用到网络技术...通过不断实践和学习,你可以更好地掌握Android网络编程,为你的应用提供强大的网络功能。

    安卓Android源码——Android版FTP服务器 SwiFTP源代码.zip

    本文将深入探讨SwiFTP的源代码,解析其核心原理,并介绍如何在Android应用开发中实现FTP服务器。 SwiFTP的实现基于Java FTP服务器库,它将标准的FTP协议转换为可以在Android系统上运行的代码。FTP(File Transfer ...

    安卓Android源码——RssReader.zip

    【安卓Android源码——RssReader.zip】是一个包含Android应用程序源代码的压缩包,主要功能是实现RSS阅读器。RSS(Really Simple Syndication)是一种内容发布格式,常用于新闻、博客和其他在线内容的聚合,使得用户...

    安卓Android源码——驴友社交系统源码.zip

    【安卓Android源码——驴友社交系统源码.zip】是一个包含安卓应用开发源代码的压缩包,主要针对驴友社交这一特定应用场景。该系统旨在为爱好旅行的用户提供一个互动交流的平台,可能包括功能如发布旅行日志、分享...

    Android源码——仿QQ客户端及服务端源码.zip

    《Android源码——仿QQ客户端及服务端源码》是一个针对Android平台的开源项目,旨在模仿QQ客户端和...通过深入研究,不仅可以理解QQ客户端的核心功能实现,还能学习到Android开发的最佳实践和服务器端的设计原则。

Global site tag (gtag.js) - Google Analytics