Android网络编程—同时上传参数和文件到服务器 [转载]
转自http://blog.csdn.net/carterjin/article/details/7571915
的三种方法为:
第一种:形如 "http://host:port/xxx/xxx/xxx/param?param1=xxx¶m2=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。
代码如下
- public class UploadUtil {
- static String INTERNAL_HOST = "http://host:port/xxx/xxx/xxx/upload/";
- }
这个主机是在第一种方法的地址中,位于“param?”前面的部分。
完成第一种方法:
第一种方法的“http://host:port/xxx/xxx/xxx/param?param1=xxx¶m2=xxx”,其实已经给出了POST的参数,param1和param2,我为了弄着方便,就直接写死了参数键值。其实也可以在方法内部,通过传入的参数,进行循环拼装,最后只要能组出类似“http://host:port/xxx/xxx/xxx/param?param1=xxx¶m2=xxx”的字符串就行,最后通过URL来生成一个url对象即可。
- public static void queryParam(String fileName)
- {
- String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线
- File file = new File(fileName); // 要上传的文件
- String host = INTERNAL_HOST + "param?param1=xxx¶m2=xxx"; // 这个字符串就是要上传的带参数的服务器地址
- try
- {
- byte[] after = ("--" + BOUNDARY + "--\r\n").getBytes("UTF-8");
- // 构造URL和Connection
- URL url = new URL(host);
- HttpURLConnection conn = (HttpURLConnection)url.openConnection();
- // 设置HTTP协议的头属性
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
- conn.setRequestProperty("Content-Length", String.valueOf(file.length()));
- conn.setRequestProperty("HOST", url.getHost());
- conn.setDoOutput(true);
- // 得到Connection的OutputStream流,准备写数据
- OutputStream out = conn.getOutputStream();
- InputStream in = new FileInputStream(file);
- // 写文件数据。因为服务器地址已经带有参数了,所以这里只要直接写入文件部分就可以了。
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) != -1)
- {
- out.write(buf, 0, len);
- }
- // 数据结束标志,整个HTTP报文就构造结束了。
- //out.write(after);
- in.close();
- out.close();
- Log.d("carter", "queryParam 返回码为: " + conn.getResponseCode());
- Log.d("carter", "queryParam 返回信息为: " + conn.getResponseMessage());
- }
- catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
大概的步骤:
1.先构造好URL服务器地址
2.初始化一个URL对象,得到里面的HttpURLConnection对象
3.设置connection对象的头部信息,包括POST方法、HOST、Content-Type、Content-Length等属性
4.写入要上传的文件内容
完成第二种方法:
第二种的方法,不想第一种方法那样简单,但基本语法结构都相似,因为都是模仿HTTP协议的形式。
第二种方法,在服务器地址上,只提供了上传的HOST和PATH,具体的参数没有提供,所以要通过在HTTP报文中添加来实现。
- public static void multiPart(String fileName)
- {
- String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线
- File file = new File(fileName); // 要上传的文件
- // 构造param参数部分的数据内容,格式都是相同的,依次添加param1和param2
- StringBuilder sb = new StringBuilder();
- sb.append("--" + BOUNDARY + "\r\n");
- sb.append("Content-Disposition: form-data; name=\"param1\"" + "\r\n");
- sb.append("\r\n");
- sb.append("xxx" + "\r\n");
- sb.append("--" + BOUNDARY + "\r\n");
- sb.append("Content-Disposition: form-data; name=\"param2\"" + "\r\n");
- sb.append("\r\n");
- sb.append("xxx" + "\r\n");
- // 构造要上传文件的前段参数内容,和普通参数一样,在这些设置后就可以紧跟文件内容了。
- sb.append("--" + BOUNDARY + "\r\n");
- sb.append("Content-Disposition: form-data; name=\"data\"; filename=\"" + fileName + "\"" + "\r\n");
- sb.append("Content-Type: text/plain" + "\r\n");
- sb.append("\r\n");
- try
- {
- byte[] before = sb.toString().getBytes("UTF-8");
- byte[] after = ("--" + BOUNDARY + "--\r\n").getBytes("UTF-8");
- URL url = new URL(INTERNAL_HOST);
- // 得到HttpURLConnection对象,设置一些头信息基本属性
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
- conn.setRequestProperty("Content-Length", String.valueOf(before.length + file.length() + after.length));
- conn.setRequestProperty("HOST", url.getHost());
- conn.setDoOutput(true);
- OutputStream out = conn.getOutputStream();
- InputStream in = new FileInputStream(file);
- // 写入参数信息
- out.write(before);
- // 写入文件数据
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) != -1)
- {
- out.write(buf, 0, len);
- }
- // 写结束符,代表该HTTP组包完毕
- out.write(after);
- // 发送出去
- out.flush();
- // 关闭流
- in.close();
- out.close();
- Log.d("carter", "multipart 返回码为: " + conn.getResponseCode());
- Log.d("carter", "multipart 返回信息为: " + conn.getResponseMessage());
- }
- catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
具体步骤为:
1.分别把param1等参数通过格式组织起来
2.得到HttpURLConnection对象,设置一些基本头属性,其中的Content-Length是所有param和文件加上尾标志的总长度。
3.发送outputStream。
完成第三种方法:
第三种方法和第二种方法很相似,只是使用了Socket对象,而不是HttpURLConnection方法。
- public static void socket(String fileName)
- {
- String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线
- File file = new File(fileName); // 要上传的文件
- // 构造参数内容字符串
- StringBuilder textParam = new StringBuilder();
- textParam.append("--" + BOUNDARY + "\r\n");
- textParam.append("Content-Disposition: form-data; name=\"param1\"" + "\r\n");
- textParam.append("\r\n");
- textParam.append("xxx" + "\r\n");
- textParam.append("--" + BOUNDARY + "\r\n");
- textParam.append("Content-Disposition: form-data; name=\"param2\"" + "\r\n");
- textParam.append("\r\n");
- textParam.append("xxx" + "\r\n");
- // 构造文件内容字符串
- int fileDataLen = 0; // 文件内容的长度
- StringBuilder fileParam = new StringBuilder();
- fileParam.append("--" + BOUNDARY + "\r\n");
- fileParam.append("Content-Disposition: form-data;name=\"data\";" + "filename=\"" + fileName + "\"" + "\r\n");
- fileParam.append("Content-Type: text/plain" + "\r\n\r\n");
- fileParam.append("\r\n");
- // 得到文件内容前的声明信息长度
- fileDataLen += fileParam.length();
- // 得到声明信息和文件内容总长度
- fileDataLen += file.length();
- // HTTP报文数据总长度
- int totalDataLen = 0;
- try
- {
- byte[] textEntity = textParam.toString().getBytes();
- byte[] after = ("--" + BOUNDARY + "--\r\n").getBytes();
- // 得到报文内数据总长度,参数声明信息+文件信息+报文尾标志信息
- totalDataLen = textEntity.length + fileDataLen + after.length;
- // 得到Socket
- URL url = new URL(INTERNAL_HOST);
- Socket socket = new Socket(url.getHost(), 80);
- socket.setSoTimeout(60000); // 设置Socket超时时间
- // 得到输出流,靠它去发送报文
- OutputStream out = socket.getOutputStream();
- // 设置请求方法
- String requestMethod = "POST " + url.getPath() + " HTTP/1.1\r\n";
- out.write(requestMethod.getBytes());
- // 设置接收类型
- String accept = "Accept: image/gif, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml," +
- "application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, " +
- "application/vnd.ms-powerpoint, application/msword, */*\r\n";
- out.write(accept.getBytes());
- // 设置语言
- String language = "Accept-Language: zh-CN\r\n";
- out.write(language.getBytes());
- // 设置内容类型
- String contentType = "Content-Type: multipart/form-data; boundary=" + BOUNDARY + "\r\n";
- out.write(contentType.getBytes());
- // 设置报文长度
- String contentLength = "Content-Length: " + totalDataLen + "\r\n";
- out.write(contentLength.getBytes());
- // 设置活动
- String alive = "Connection: Keep-Alive\r\n";
- out.write(alive.getBytes());
- // 设置主机
- String host = "Host: " + url.getHost() + ":80\r\n";
- out.write(host.getBytes());
- // 设置一个回车换行
- out.write("\r\n".getBytes());
- // 添加所有文本类型数据
- out.write(textEntity);
- // 添加所有文件类型数据
- StringBuilder fileEntity = new StringBuilder();
- fileEntity.append("--" + BOUNDARY + "\r\n");
- fileEntity.append("Content-Disposition: form-data;name=\"data\";" + "filename=\"" + fileName + "\"" + "\r\n");
- fileEntity.append("Content-Type: text/plain" + "\r\n\r\n");
- out.write(fileEntity.toString().getBytes());
- // 将文件内容写入报文
- FileInputStream fis = new FileInputStream(file); // 以后记得加null判断
- byte[] buffer = new byte[1024];
- int len = 0;
- while( (len=fis.read(buffer))!=-1 )
- {
- out.write(buffer, 0, len);
- }
- fis.close();
- out.write("\r\n".getBytes());
- // 数据结束标志,代表数据已经结束
- out.write(after);
- // 输出处理结果
- BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- String line = "";
- while( (line=reader.readLine())!=null)
- {
- Log.d("carter", line);
- }
- // 发送报文
- out.flush();
- // 关闭流
- out.close();
- reader.close();
- socket.close();
- }
- catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
具体步骤:
1.构造参数信息
2.构造文件信息
3.构造尾信息
4.通过URL和端口得到一个Socket对象
5.设置Socket的属性
6.得到一个输出流,将所有信息输出
7.输出传送结果