请尊重他人的劳动成果,转载请注明出处:Android网络编程之使用HttpClient批量上传文件

http://www.tuicool.com/articles/Y7reYb

我曾在《Android网络编程之使用HTTP访问网络资源》一文中介绍过HttpCient的使用,这里就不在累述了,感兴趣的朋友可以去看一下。在这里主要介绍如何通过HttpClient实现文件上传。

1.预备知识:


在HttpCient4.3之前上传文件主要使用MultipartEntity这个类,但现在这个类已经不在推荐使用了。随之替代它的类是MultipartEntityBuilder。

下面让我们了解一下MultipartEntityBuilder类:

MultipartEntityBuilder这个类主要用于创建HttpEntity。它的主要方法有:

修饰符和类型

方法和描述

MultipartEntityBuilder

addBinaryBody(String name, byte[] b)

将字节数组以二进制的形式添加数据。

MultipartEntityBuilder

addBinaryBody(String name, byte[] b, ContentType contentType, String filename)

将字节数组以二进制的形式添加数据。

MultipartEntityBuilder

addBinaryBody(String name, File file)

将文件以二进制的形式添加数据。

MultipartEntityBuilder

addBinaryBody(String name, File file, ContentType contentType, String filename)

将文件以二进制的形式添加数据。

MultipartEntityBuilder

addBinaryBody(String name, InputStream stream)

MultipartEntityBuilder

addBinaryBody(String name, InputStream stream, ContentType contentType, String filename)

将输入流以二进制的形式添加数据。

MultipartEntityBuilder

addPart(String name, ContentBody contentBody)

添加ContentBody 类型的数据。

MultipartEntityBuilder

addTextBody(String name, String text)

添加文本数据。

MultipartEntityBuilder

addTextBody(String name, String text, ContentType contentType)

以指定的内容类型添加文本数据。

HttpEntity

build()

创建一个HttpEntity。

static MultipartEntityBuilder

create()

创建一个MultipartEntityBuilder对象。

MultipartEntityBuilder

setBoundary(String boundary)

设置边界。

MultipartEntityBuilder

setCharset(Charset charset)

设置请求的编码格式。

MultipartEntityBuilder

setLaxMode()

MultipartEntityBuilder

setMode(HttpMultipartMode mode)

设置模式。

MultipartEntityBuilder

setStrictMode()

主要方法说明:

addBinaryBodyaddPartaddTextBody方法用于添加要上传的数据,从上面的表格中可以发现用于添加数据的方法,都是key-value类型。所以在服务器端我们可以通过request.getPart("keyname")方式获取对应key的数据。也可以通过request.getParts()方式获取客户端通过以上三种方法提交所有数据。

1.通过addBinaryBody方法直接可以添加File、InputStream、byte[]类型的数据。

2.通过addPart方法只能添加ContentBody类型的数据,在org.apache.http.entity.mime.content包中已经提供了StringFile以及InputStream对应的ContentBody类型的子类,如FileBody、InputStreamBody、StringBody,通过这些类我们可以将String、File以及InputStream类型的数据转换成ContentBody类型的数据。

3.通过addTextBody方法我们可以很方便的添加文本数据。

2.通过HttpCient上传文件


Android端需要添加httpcore-4.3.2.jarhttpmime-4.3.5.jar两个包。两个包缺一不可。

在这里我用的是最新版的HttpCient,大家可以从http://hc.apache.org/downloads.cgi上下载所需要的jar包,如果上面的网站打不开,大家也不用担心,我已经将项目中所需要的jar包上传到CSDN上《httpcomponents-client-4.3.5-bin.zip》需要的朋友可以去下载。

Android端项目核心代码:

HttpClient client=new DefaultHttpClient();// 开启一个客户端 HTTP 请求
HttpPost post = new HttpPost(url);//创建 HTTP POST 请求
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
// builder.setCharset(Charset.forName("uft-8"));//设置请求的编码格式
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//设置浏览器兼容模式
int count=0;
for (File file:files) {
// FileBody fileBody = new FileBody(file);//把文件转换成流对象FileBody
// builder.addPart("file"+count, fileBody);
builder.addBinaryBody("file"+count, file);
count++;
}
builder.addTextBody("method", params.get("method"));//设置请求参数
builder.addTextBody("fileTypes", params.get("fileTypes"));//设置请求参数
HttpEntity entity = builder.build();// 生成 HTTP POST 实体
post.setEntity(entity);//设置请求参数
HttpResponse response = client.execute(post);// 发起请求 并返回请求的响应
if (response.getStatusLine().getStatusCode()==200) {
return true;
}
return false;

代码分析:

上面代码主要实现了多文件上传,为了方便服务器端保存文件,上面代码设置了名称为fileTypes的参数,fileTypes是由上传的文件类型名拼接成的字符串,如”.jpg.png.docx“;

服务器端可以通过获取名为fileTypes的参数,然后将其拆分成字符数组,即可得到要保存文件的类型。

服务器端项目核心代码:

服务器段主要用到Servlet3.0的API,主要用到的方法有:

1.      request.getParameter("");//获取客户端通过addTextBody方法添加的String类型的数据。

2.      request.getPart("");//获取客户端通过addBinaryBodyaddPartaddTextBody方法添加的指定数据,返回Part类型的对象。

3.      request.getParts();//获取客户端通过addBinaryBodyaddPartaddTextBody方法添加的所有数据,返回Collection<Part>类型的对象。

4.      part.getName();//获取上传文件的名称即上传时指定的key。

5.      part.getSize()//获取上传文件的大小单位为字节。

String fileTypes=request.getParameter("fileTypes");//获取客户端上传的所有文件类型
String[]typeArray=fileTypes.substring(1).split("\\.");//将文件类型字符串拆分成String数组
try {
Iterator<Part>iterator=request.getParts().iterator();
int count=0;
while (iterator.hasNext()) {//遍历客户端上传的所有文件
if (count>=typeArray.length)break;//如果超出文件类型数组的大小则跳出循环
Part part = (Part) iterator.next();
// System.out.println("part.getSize()"+part.getSize());//获取上传文件的大小
// System.out.println("part.getName()"+part.getName());//获取上传文件的名及添加数据时的key名
File file=new File("E:\\upload\\"+count+"."+typeArray[count++]);
InputStream inputStream=part.getInputStream();
FileOutputStream fos=new FileOutputStream(file);
byte[]buffer=new byte[1024];
int len=0;
while ((len=inputStream.read(buffer))!=-1) {
fos.write(buffer,0, len);
}
inputStream.close();
fos.close();
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

代码分析:

服务器端是通过Servlet实现的,通过调用request.getParameter("fileTypes")方法来获取客户端上传的所有文件类型,然后将文件类型字符串拆分成String数组。通过request.getParts()方法取出客户端通过addBinaryBodyaddPartaddTextBody上传的所有数据,然后遍历数据集合即可进行文件的保存。

由于事先和客户端协定,添加上传文件的顺序在添加请求参数之前,所以可以根据拆分出的文件类型数组的长度判断出客户端上传文件的个数,因此当上面代码遍历超出了类型数组的长度时程序跳出循环,不再进行文件的保存,因为下面的Part都是些参数,而不是要保存的文件了。

程序运行效果图:


 
 

3.完成项目代码:


MainActivity.java
package com.jph.ufh.activity;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.jph.ufh.R;
import com.jph.ufh.service.UploadService;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Toast; /**
* 通过httpClient批量上传文件
* @author jph
* Date:2014.10.09
*/
public class MainActivity extends Activity {
private ArrayList<File>files;
private Map<String, String>params;
Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case UploadService.UPLOAD_SUCCESS:
Toast.makeText(MainActivity.this, "上传成功", Toast.LENGTH_LONG).show();
break;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
files=new ArrayList<File>();
params=new HashMap<String, String>(); }
public void upload(View v) {
files.clear();
params.clear();
File file=new File(Environment.getExternalStorageDirectory(),"kaola.jpg");
File file2=new File(Environment.getExternalStorageDirectory(),"test.docx");
File file3=new File(Environment.getExternalStorageDirectory(),"test.jpg");
files.add(file);
files.add(file2);
files.add(file3);
StringBuffer sbFileTypes=new StringBuffer();
for (File tempFile:files) {
String fileName=tempFile.getName();
sbFileTypes.append(getFileType(fileName));
}
params.put("fileTypes",sbFileTypes.toString());
params.put("method", "upload");
UploadService uploadService=new UploadService(mHandler);
uploadService.uploadFileToServer(params, files);
}
/**
* 获取文件的类型
* @param fileName :文件名
* @return 文件类型
*/
private String getFileType(String fileName) {
// TODO Auto-generated method stub
return fileName.substring(fileName.lastIndexOf("."), fileName.length());
}
}
UploadService.java
package com.jph.ufh.service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.DefaultHttpClient; import android.os.Handler; /**
* 采用HttpClient上传文件,支持多文件上传
* @author jph
* Date:2014.10.09
*/
public class UploadService {
private static String url="http://10.219.57.16:8080/ServerForUpload/ServletForUpload";
// private static String url="http://10.110.6.58:8080/ServerForUpload/ServletForUpload";
public static final int UPLOAD_SUCCESS=0x123;
public static final int UPLOAD_FAIL=0x124;
private Handler handler;
public UploadService(Handler handler) {
// TODO Auto-generated constructor stub
this.handler=handler;
}
/**
* @param params 请求参数,包括请求的的方法参数method如:“upload”,
* 请求上传的文件类型fileTypes如:“.jpg.png.docx”
* @param files 要上传的文件集合
*/
public void uploadFileToServer(final Map<String, String> params, final ArrayList<File>files) {
// TODO Auto-generated method stub
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
if (uploadFiles(url,params,files)) {
handler.sendEmptyMessage(UPLOAD_SUCCESS);//通知主线程数据发送成功
}else {
//将数据发送给服务器失败
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
/**
* @param url servlet的地址
* @param params 要传递的参数
* @param files 要上传的文件
* @return true if upload success else false
* @throws ClientProtocolException
* @throws IOException
*/
private boolean uploadFiles(String url,Map<String, String>params,ArrayList<File>files) throws ClientProtocolException, IOException {
HttpClient client=new DefaultHttpClient();// 开启一个客户端 HTTP 请求
HttpPost post = new HttpPost(url);//创建 HTTP POST 请求
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
// builder.setCharset(Charset.forName("uft-8"));//设置请求的编码格式
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//设置浏览器兼容模式
int count=0;
for (File file:files) {
// FileBody fileBody = new FileBody(file);//把文件转换成流对象FileBody
// builder.addPart("file"+count, fileBody);
builder.addBinaryBody("file"+count, file);
count++;
}
builder.addTextBody("method", params.get("method"));//设置请求参数
builder.addTextBody("fileTypes", params.get("fileTypes"));//设置请求参数
HttpEntity entity = builder.build();// 生成 HTTP POST 实体
post.setEntity(entity);//设置请求参数
HttpResponse response = client.execute(post);// 发起请求 并返回请求的响应
if (response.getStatusLine().getStatusCode()==200) {
return true;
}
return false;
}
}

转 Android网络编程之使用HttpClient批量上传文件 MultipartEntityBuilder的更多相关文章

  1. Android利用网络编程HttpClient批量上传(一个)

    请尊重他人的劳动成果.转载请注明出处:Android网络编程之使用HttpClient批量上传文件 我曾在<Android网络编程之使用HTTP訪问网络资源>一文中介绍过HttpCient ...

  2. Android利用网络编程HttpClient批量上传(两)AsyncTask+HttpClient监测进展情况,并上传

    请尊重别人的劳动.转载请注明出处: Android网络编程之使用HttpClient批量上传文件(二)AsyncTask+HttpClient并实现上传进度监听 执行效果图: 我曾在<Andro ...

  3. Linux命令之rz - 批量上传文件,简单易用(转载)

    用途说明 rz命令能够批量上传文件,当然也可上传单个文件啦.使用的协议是古老的ZMODEM协议,尽管协议古老,但毫不影响的简单易用的特性.一般情 况我们要上传文件到Linux系统,要么使用ftp(还得 ...

  4. 不带插件 ,自己写js,实现批量上传文件及进度显示

    今天接受项目中要完成文件批量上传文件而且还要显示上传进度,一开始觉得这个应该不是很麻烦,当我在做的时候遇到了很多问题,很头疼啊. 不过看了别人写的代码,自己也测试过,发现网上好多都存在一些问题,并不是 ...

  5. Python基于Python实现批量上传文件或目录到不同的Linux服务器

    基于Python实现批量上传文件或目录到不同的Linux服务器   by:授客 QQ:1033553122 实现功能 1 测试环境 1 使用方法 1 1. 编辑配置文件conf/rootpath_fo ...

  6. input file multiple 批量上传文件

    这几天维护系统,有一个批量上传文件功能,出现了一点小问题 我的笔记本选择要上传的文件很正常 但在测试环境上,别人的电脑上,选择上传文件之后 一开始,以为是代码问题,网上找了很多的资料,但还是没用,然后 ...

  7. 使用 sendKeys(keysToSend) 批量上传文件

    未经允许,禁止转载!!! 在selenium里面处理文件上传的时候可以使用sendKeys(keysToSend) 上传文件 例如: element.sendKeys(“C:\\test\\uploa ...

  8. TP3.2批量上传文件(图片),解决同名冲突问题

    1.html <form action="{:U('Upload/index')}" enctype="multipart/form-data" meth ...

  9. 用Azure CLI批量上传文件

    在Windows环境下,我们可以使用AzCopy批量上传文件.其效率和传输速率都是非常快的. 在Linux或MacOS环境下,可以使用Azure的CLI实现批量文件的上传. 下面的脚本可以实现此功能. ...

随机推荐

  1. 转载-SharePoint 2010 WebPart与Google地图系列 一:创建显示地图的WebPart

    [原] SharePoint 2010 WebPart与Google地图系列 一:创建显示地图的WebPart 摘要: 作为信息化先驱的产品SharePoint 2010竟然对GIS相关技术支持如此有 ...

  2. 图解HTTP读书笔记--精简版

    这本书重点讲了两点,分别是 HTTP的报文格式 HTTPS比HTTP优秀在哪里 接下来分部分讨论一下: 1. HTTP的报文格式 请求报文格式: 请求行     指明请求方法 请求路径 和协议   如 ...

  3. 改变vim配色:安装colorscheme【转】

    主要有两种方式安装colorscheme: 自行下载colorscheme安装,下载的文件扩展名通常为.vim. 通过安装相关vim的插件获取. 自行下载colorscheme安装 以mac为例,在系 ...

  4. and的用法(&)

    经常看到jq的源码中各种&连接在一起赋值一个变量, 例一: var b = a&&a.getName 例二: var b = a&&a.getName||d 例 ...

  5. 格式化格林威治时间(Wed Aug 01 00:00:00 CST 2012)

    1.如果格林威治时间时间是date类型.(这种格式最简单)       SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd") ...

  6. CodeForces 510B DFS水题

    题目大意:在图中找到一个字符可以围成一个环(至少有环四个相同元素) 题目思路:对当前点进行搜索,如果发现可以达到某个已经被查找过的点,且当前点不是由这个点而来,则查找成功. #include<c ...

  7. java 反射的实例

    JAVA反射机制是在运行状态中,对于任意一个类,都能够得到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制 ...

  8. php 四种基础算法 ---- 插入排序法

    3.插入排序法 插入排序法思路:将要排序的元素插入到已经 假定排序号的数组的指定位置. 代码: function insert_sort($arr) {    //区分 哪部分是已经排序好的    / ...

  9. js表单提交,判断文本框,用户名密码是否为空,JS表单检测!

    当表单提交时先触发验证的js代码,当验证表单的方法返回true时才会提交表单返回false则不提交数据<script type="text/javascript">fu ...

  10. UVA - 10048 Audiophobia (Floyd应用)

    题意:求出两点之间所有路径最大权值的最小值. 思路:转变一下Floyd的形式即可: 注意:注意初始化问题,还有UVA奇葩的输出形式. 代码如下: #include<iostream> #i ...