Android网络编程—同时上传参数和文件到服务器

 

Android网络编程—同时上传参数和文件到服务器

分类: android 网络 post 上传文件   599人阅读  评论(1)  收藏  举报
android 编程 网络 string socket file

毕业两年了,也工作两年了,但是由于具体的工作内容原因,真正去按照老大的要求去写一个程序,还是第一次。

这次就遇到了一个问题,从来没有接触过的Android网络编程,需求是按照指定的三种方法,以POST方法,分别用HTTP和Socket上传一个文件到服务器。


指定的三种方法为:

第一种:形如 "http://host:port/xxx/xxx/xxx/param?param1=xxx&param2=xxx"的形式

Params:

      param1

      param2

Data:

      file:要上传的文件

第二种:形如“http://host:port/xxx/xxx/xxx”的形式

Part1:

      param1

Part2:

      param2

Part3:

      file:要上传的文件

第三种:形如“http://host:port/xxx/xxx/xxx”的形式

Part1:

      param1

Part2:

      param2

Part3:

      file:要上传的文件

利用Socket方法来发送



三种方法,首先搞得我头晕脑胀,纠结了整整一天,后来终于理顺了一些,现在把这些方法陈列出来,大家来批评指正,有不对的地方及时通知我来进行修改,大家共勉。

第一种和第二种都是模拟HTTP协议来发送的,使用HttpURLConnection类来发送,第三种使用Socket方法来发送。


首先我定义了一个上传工具类:UploadUtil.java,里面只是定义了一个Static的服务器地址,INTERNAL_HOST。

代码如下

[java]  view plain copy
  1. public class UploadUtil {  
  2.       
  3.     static String INTERNAL_HOST = "http://host:port/xxx/xxx/xxx/upload/";  
  4.       
  5. }  

这个主机是在第一种方法的地址中,位于“param?”前面的部分。




完成第一种方法:

第一种方法的“http://host:port/xxx/xxx/xxx/param?param1=xxx&param2=xxx”,其实已经给出了POST的参数,param1和param2,我为了弄着方便,就直接写死了参数键值。其实也可以在方法内部,通过传入的参数,进行循环拼装,最后只要能组出类似“http://host:port/xxx/xxx/xxx/param?param1=xxx&param2=xxx”的字符串就行,最后通过URL来生成一个url对象即可。

[java]  view plain copy
  1. public static void queryParam(String fileName)  
  2.     {  
  3.         String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线  
  4.         File file = new File(fileName);   // 要上传的文件  
  5.         String host = INTERNAL_HOST + "param?param1=xxx¶m2=xxx"// 这个字符串就是要上传的带参数的服务器地址  
  6.           
  7.           
  8.         try   
  9.         {  
  10.             byte[] after = ("--" + BOUNDARY + "--\r\n").getBytes("UTF-8");  
  11.               
  12.             // 构造URL和Connection  
  13.             URL url = new URL(host);              
  14.             HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
  15.               
  16.             // 设置HTTP协议的头属性  
  17.             conn.setRequestMethod("POST");  
  18.             conn.setRequestProperty("Content-Type""multipart/form-data; boundary=" + BOUNDARY);  
  19.             conn.setRequestProperty("Content-Length", String.valueOf(file.length()));  
  20.             conn.setRequestProperty("HOST", url.getHost());  
  21.             conn.setDoOutput(true);  
  22.               
  23.             // 得到Connection的OutputStream流,准备写数据  
  24.             OutputStream out = conn.getOutputStream();  
  25.             InputStream in = new FileInputStream(file);  
  26.               
  27.               
  28.             // 写文件数据。因为服务器地址已经带有参数了,所以这里只要直接写入文件部分就可以了。  
  29.             byte[] buf = new byte[1024];  
  30.             int len;  
  31.             while ((len = in.read(buf)) != -1)  
  32.             {  
  33.                 out.write(buf, 0, len);  
  34.             }               
  35.   
  36.             // 数据结束标志,整个HTTP报文就构造结束了。  
  37.             //out.write(after);  
  38.   
  39.             in.close();  
  40.             out.close();  
  41.               
  42.             Log.d("carter""queryParam 返回码为: " + conn.getResponseCode());  
  43.             Log.d("carter""queryParam 返回信息为: " + conn.getResponseMessage());  
  44.               
  45.         }  
  46.         catch (MalformedURLException e) {  
  47.             // TODO Auto-generated catch block  
  48.             e.printStackTrace();  
  49.         } catch (IOException e) {  
  50.             // TODO Auto-generated catch block  
  51.             e.printStackTrace();  
  52.         }  
  53.     }  

大概的步骤:

1.先构造好URL服务器地址

2.初始化一个URL对象,得到里面的HttpURLConnection对象

3.设置connection对象的头部信息,包括POST方法、HOST、Content-Type、Content-Length等属性

4.写入要上传的文件内容




完成第二种方法:

第二种的方法,不想第一种方法那样简单,但基本语法结构都相似,因为都是模仿HTTP协议的形式。

第二种方法,在服务器地址上,只提供了上传的HOST和PATH,具体的参数没有提供,所以要通过在HTTP报文中添加来实现。


[java]  view plain copy
  1. public static void multiPart(String fileName)  
  2.     {  
  3.         String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线  
  4.         File file = new File(fileName);   // 要上传的文件  
  5.           
  6.         // 构造param参数部分的数据内容,格式都是相同的,依次添加param1和param2  
  7.         StringBuilder sb = new StringBuilder();  
  8.         sb.append("--" + BOUNDARY + "\r\n");  
  9.         sb.append("Content-Disposition: form-data; name=\"param1\"" + "\r\n");  
  10.         sb.append("\r\n");  
  11.         sb.append("xxx" + "\r\n");  
  12.   
  13.         sb.append("--" + BOUNDARY + "\r\n");  
  14.         sb.append("Content-Disposition: form-data; name=\"param2\"" + "\r\n");  
  15.         sb.append("\r\n");  
  16.         sb.append("xxx" + "\r\n");  
  17.   
  18.                 // 构造要上传文件的前段参数内容,和普通参数一样,在这些设置后就可以紧跟文件内容了。  
  19.         sb.append("--" + BOUNDARY + "\r\n");  
  20.         sb.append("Content-Disposition: form-data; name=\"data\"; filename=\"" + fileName + "\"" + "\r\n");  
  21.         sb.append("Content-Type: text/plain" + "\r\n");  
  22.         sb.append("\r\n");  
  23.           
  24.         try   
  25.         {  
  26.             byte[] before = sb.toString().getBytes("UTF-8");  
  27.             byte[] after = ("--" + BOUNDARY + "--\r\n").getBytes("UTF-8");  
  28.             URL url = new URL(INTERNAL_HOST);  
  29.               
  30.             // 得到HttpURLConnection对象,设置一些头信息基本属性  
  31.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  32.             conn.setRequestMethod("POST");  
  33.             conn.setRequestProperty("Content-Type""multipart/form-data; boundary=" + BOUNDARY);  
  34.             conn.setRequestProperty("Content-Length", String.valueOf(before.length + file.length() + after.length));  
  35.             conn.setRequestProperty("HOST", url.getHost());  
  36.             conn.setDoOutput(true);  
  37.               
  38.             OutputStream out = conn.getOutputStream();  
  39.             InputStream in = new FileInputStream(file);  
  40.               
  41.             // 写入参数信息  
  42.             out.write(before);  
  43.   
  44.             // 写入文件数据  
  45.             byte[] buf = new byte[1024];  
  46.             int len;  
  47.             while ((len = in.read(buf)) != -1)  
  48.             {  
  49.                 out.write(buf, 0, len);  
  50.             }               
  51.   
  52.             // 写结束符,代表该HTTP组包完毕  
  53.             out.write(after);  
  54.               
  55.             // 发送出去  
  56.             out.flush();  
  57.   
  58.             // 关闭流  
  59.             in.close();  
  60.             out.close();  
  61.               
  62.             Log.d("carter""multipart 返回码为: " + conn.getResponseCode());  
  63.             Log.d("carter""multipart 返回信息为: " + conn.getResponseMessage());  
  64.         }  
  65.         catch (MalformedURLException e) {  
  66.             // TODO Auto-generated catch block  
  67.             e.printStackTrace();  
  68.         } catch (UnsupportedEncodingException e) {  
  69.             // TODO Auto-generated catch block  
  70.             e.printStackTrace();  
  71.         } catch (IOException e) {  
  72.             // TODO Auto-generated catch block  
  73.             e.printStackTrace();  
  74.         }  
  75.     }  

具体步骤为:

1.分别把param1等参数通过格式组织起来

2.得到HttpURLConnection对象,设置一些基本头属性,其中的Content-Length是所有param和文件加上尾标志的总长度。

3.发送outputStream。




完成第三种方法:

第三种方法和第二种方法很相似,只是使用了Socket对象,而不是HttpURLConnection方法。


[java]  view plain copy
  1. public static void socket(String fileName)  
  2.   {  
  3.       String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线  
  4.       File file = new File(fileName);   // 要上传的文件  
  5.         
  6.       // 构造参数内容字符串  
  7.       StringBuilder textParam = new StringBuilder();  
  8.       textParam.append("--" + BOUNDARY + "\r\n");  
  9.       textParam.append("Content-Disposition: form-data; name=\"param1\"" + "\r\n");  
  10.       textParam.append("\r\n");  
  11.       textParam.append("xxx" + "\r\n");  
  12.   
  13.       textParam.append("--" + BOUNDARY + "\r\n");  
  14.       textParam.append("Content-Disposition: form-data; name=\"param2\"" + "\r\n");  
  15.       textParam.append("\r\n");  
  16.       textParam.append("xxx" + "\r\n");  
  17.         
  18.       // 构造文件内容字符串  
  19.       int fileDataLen = 0;    // 文件内容的长度  
  20.       StringBuilder fileParam = new StringBuilder();  
  21.       fileParam.append("--" + BOUNDARY + "\r\n");  
  22.       fileParam.append("Content-Disposition: form-data;name=\"data\";" + "filename=\"" + fileName + "\"" + "\r\n");  
  23.       fileParam.append("Content-Type: text/plain" + "\r\n\r\n");  
  24.       fileParam.append("\r\n");  
  25.         
  26.       // 得到文件内容前的声明信息长度  
  27.       fileDataLen += fileParam.length();  
  28.       // 得到声明信息和文件内容总长度  
  29.       fileDataLen += file.length();  
  30.         
  31.       // HTTP报文数据总长度  
  32.       int totalDataLen = 0;  
  33.         
  34.       try   
  35.       {  
  36.           byte[] textEntity = textParam.toString().getBytes();  
  37.           byte[] after = ("--" + BOUNDARY + "--\r\n").getBytes();  
  38.           // 得到报文内数据总长度,参数声明信息+文件信息+报文尾标志信息  
  39.           totalDataLen = textEntity.length + fileDataLen + after.length;  
  40.             
  41.           // 得到Socket  
  42.           URL url = new URL(INTERNAL_HOST);              
  43.           Socket socket = new Socket(url.getHost(), 80);  
  44.           socket.setSoTimeout(60000);   // 设置Socket超时时间  
  45.             
  46.           // 得到输出流,靠它去发送报文  
  47.           OutputStream out = socket.getOutputStream();  
  48.             
  49.           // 设置请求方法  
  50.           String requestMethod = "POST " + url.getPath() + " HTTP/1.1\r\n";  
  51.           out.write(requestMethod.getBytes());  
  52.             
  53.           // 设置接收类型  
  54.           String accept = "Accept: image/gif, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml," +  
  55.                 "application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, " +  
  56.                 "application/vnd.ms-powerpoint, application/msword, */*\r\n";  
  57.           out.write(accept.getBytes());  
  58.             
  59.           // 设置语言  
  60.           String language = "Accept-Language: zh-CN\r\n";  
  61.           out.write(language.getBytes());  
  62.             
  63.           // 设置内容类型  
  64.           String contentType = "Content-Type: multipart/form-data; boundary=" + BOUNDARY + "\r\n";  
  65.           out.write(contentType.getBytes());  
  66.             
  67.           // 设置报文长度  
  68.           String contentLength = "Content-Length: " + totalDataLen + "\r\n";  
  69.           out.write(contentLength.getBytes());  
  70.             
  71.           // 设置活动  
  72.           String alive = "Connection: Keep-Alive\r\n";  
  73.           out.write(alive.getBytes());  
  74.             
  75.           // 设置主机  
  76.           String host = "Host: " + url.getHost() + ":80\r\n";  
  77.           out.write(host.getBytes());  
  78.             
  79.           // 设置一个回车换行  
  80.           out.write("\r\n".getBytes());  
  81.             
  82.             
  83.           // 添加所有文本类型数据  
  84.           out.write(textEntity);  
  85.             
  86.             
  87.           // 添加所有文件类型数据  
  88.           StringBuilder fileEntity = new StringBuilder();  
  89.           fileEntity.append("--" + BOUNDARY + "\r\n");  
  90.           fileEntity.append("Content-Disposition: form-data;name=\"data\";" + "filename=\"" + fileName + "\"" + "\r\n");  
  91.           fileEntity.append("Content-Type: text/plain" + "\r\n\r\n");  
  92.           out.write(fileEntity.toString().getBytes());  
  93.             
  94.           // 将文件内容写入报文  
  95.           FileInputStream fis = new FileInputStream(file);    // 以后记得加null判断  
  96.           byte[] buffer = new byte[1024];  
  97.           int len = 0;  
  98.           while( (len=fis.read(buffer))!=-1 )  
  99.           {  
  100.               out.write(buffer, 0, len);  
  101.           }  
  102.           fis.close();  
  103.           out.write("\r\n".getBytes());  
  104.             
  105.           // 数据结束标志,代表数据已经结束  
  106.           out.write(after);  
  107.             
  108.             
  109.           // 输出处理结果  
  110.           BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
  111.           String line = "";  
  112.           while( (line=reader.readLine())!=null)  
  113.           {  
  114.               Log.d("carter", line);  
  115.           }  
  116.            
  117.           // 发送报文  
  118.           out.flush();  
  119.             
  120.           // 关闭流  
  121.           out.close();  
  122.           reader.close();  
  123.           socket.close();              
  124.       }  
  125.       catch (MalformedURLException e) {  
  126.           // TODO Auto-generated catch block  
  127.           e.printStackTrace();  
  128.       }   
  129.       catch (UnsupportedEncodingException e) {  
  130.           // TODO Auto-generated catch block  
  131.           e.printStackTrace();  
  132.       }   
  133.       catch (IOException e) {  
  134.           // TODO Auto-generated catch block  
  135.           e.printStackTrace();  
  136.       }  
  137.   }  

具体步骤:

1.构造参数信息

2.构造文件信息

3.构造尾信息

4.通过URL和端口得到一个Socket对象

5.设置Socket的属性

6.得到一个输出流,将所有信息输出

7.输出传送结果



至此,三种方法就都实现了,纠结的内容,但是需要积极的去实现。

以上方法,只要替换其中的某些参数信息,就可以完全直接复用了。

你可能感兴趣的:(android,网络,上传文件,post)