转 Android网络编程之使用HttpClient批量上传文件 MultipartEntityBuilder
请尊重他人的劳动成果,转载请注明出处: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() |
主要方法说明:
addBinaryBody、addPart、addTextBody方法用于添加要上传的数据,从上面的表格中可以发现用于添加数据的方法,都是key-value类型。所以在服务器端我们可以通过request.getPart("keyname")方式获取对应key的数据。也可以通过request.getParts()方式获取客户端通过以上三种方法提交所有数据。
1.通过addBinaryBody方法直接可以添加File、InputStream、byte[]类型的数据。
2.通过addPart方法只能添加ContentBody类型的数据,在org.apache.http.entity.mime.content包中已经提供了String、File以及InputStream对应的ContentBody类型的子类,如FileBody、InputStreamBody、StringBody,通过这些类我们可以将String、File以及InputStream类型的数据转换成ContentBody类型的数据。
3.通过addTextBody方法我们可以很方便的添加文本数据。
2.通过HttpCient上传文件
Android端需要添加httpcore-4.3.2.jar、httpmime-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("");//获取客户端通过addBinaryBody、addPart、addTextBody方法添加的指定数据,返回Part类型的对象。
3. request.getParts();//获取客户端通过addBinaryBody、addPart、addTextBody方法添加的所有数据,返回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()方法取出客户端通过addBinaryBody、addPart、addTextBody上传的所有数据,然后遍历数据集合即可进行文件的保存。
由于事先和客户端协定,添加上传文件的顺序在添加请求参数之前,所以可以根据拆分出的文件类型数组的长度判断出客户端上传文件的个数,因此当上面代码遍历超出了类型数组的长度时程序跳出循环,不再进行文件的保存,因为下面的Part都是些参数,而不是要保存的文件了。
程序运行效果图:
3.完成项目代码:
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());
}
}
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的更多相关文章
- Android利用网络编程HttpClient批量上传(一个)
请尊重他人的劳动成果.转载请注明出处:Android网络编程之使用HttpClient批量上传文件 我曾在<Android网络编程之使用HTTP訪问网络资源>一文中介绍过HttpCient ...
- Android利用网络编程HttpClient批量上传(两)AsyncTask+HttpClient监测进展情况,并上传
请尊重别人的劳动.转载请注明出处: Android网络编程之使用HttpClient批量上传文件(二)AsyncTask+HttpClient并实现上传进度监听 执行效果图: 我曾在<Andro ...
- Linux命令之rz - 批量上传文件,简单易用(转载)
用途说明 rz命令能够批量上传文件,当然也可上传单个文件啦.使用的协议是古老的ZMODEM协议,尽管协议古老,但毫不影响的简单易用的特性.一般情 况我们要上传文件到Linux系统,要么使用ftp(还得 ...
- 不带插件 ,自己写js,实现批量上传文件及进度显示
今天接受项目中要完成文件批量上传文件而且还要显示上传进度,一开始觉得这个应该不是很麻烦,当我在做的时候遇到了很多问题,很头疼啊. 不过看了别人写的代码,自己也测试过,发现网上好多都存在一些问题,并不是 ...
- Python基于Python实现批量上传文件或目录到不同的Linux服务器
基于Python实现批量上传文件或目录到不同的Linux服务器 by:授客 QQ:1033553122 实现功能 1 测试环境 1 使用方法 1 1. 编辑配置文件conf/rootpath_fo ...
- input file multiple 批量上传文件
这几天维护系统,有一个批量上传文件功能,出现了一点小问题 我的笔记本选择要上传的文件很正常 但在测试环境上,别人的电脑上,选择上传文件之后 一开始,以为是代码问题,网上找了很多的资料,但还是没用,然后 ...
- 使用 sendKeys(keysToSend) 批量上传文件
未经允许,禁止转载!!! 在selenium里面处理文件上传的时候可以使用sendKeys(keysToSend) 上传文件 例如: element.sendKeys(“C:\\test\\uploa ...
- TP3.2批量上传文件(图片),解决同名冲突问题
1.html <form action="{:U('Upload/index')}" enctype="multipart/form-data" meth ...
- 用Azure CLI批量上传文件
在Windows环境下,我们可以使用AzCopy批量上传文件.其效率和传输速率都是非常快的. 在Linux或MacOS环境下,可以使用Azure的CLI实现批量文件的上传. 下面的脚本可以实现此功能. ...
随机推荐
- 中国内地、台湾、香港、澳门和国外DNS服务器地址列表
中国内地.台湾.香港.澳门和国外DNS服务器地址列表 详细内容 作者:网路岗 来源:局域网监控软件 DNS(Domain Name System)是域名解析服务器的意思,它在互联网的作用是把域名转换成 ...
- Mongoose如何实现统计查询、关联查询
[问题]Mongoose如何实现统计查询.关联查询 发布于 4 年前 作者 a272121742 13025 次浏览 最近业务上提出一个需求,要求能做统计,我们设计的文档集,统计可能跨越的文档会 ...
- JavaScript焦点事件、鼠标事件和滚轮事件使用详解
网址:http://www.jb51.net/article/78094.htm
- linux c中select使用技巧
1.select函数作为定时器使用 it_value.tv_sec = 0; it_value.tv_usec = 100000: select(1,NULL,NULL,NULL,& ...
- perl-cgi基础
来源: http://www.cnblogs.com/itech/archive/2012/09/22/2698553.html 代码: http://xxxxx/cgi/perl-cgi.cgi?n ...
- replication factor
http://www.tuicool.com/articles/RJbIBj 关于Hadoop中replication factor解惑 时间 2014-06-09 08:00:50 ITeye ...
- 重启库,提示找不到mysqld
--ledir=/usr/local/mysql/bin 加上server的 directory https://dev.mysql.com/doc/refman/5.5/en/mysqld-s ...
- 解决oracle数据库连接不上的问题
今天打开部署好的java开发的网站系统,反应好慢,第一反应就是后台有问题. 查看tomcat一堆的报错信息,重启还是存在. 使用plSql连接数据库看看,登录提示如下:ORA-12514:TNS:监听 ...
- HDU 2018 undefined
题目思路:完全背包,dp[i][j]代表,砍j只怪,用i点疲劳最多能获得的经验值. 和平常的完全背包不一样的是多了一个限制条件:最多只砍S只怪,所以我们应该多一重循环来q:for 1->S,代表 ...
- linux进程、管道和重定向
1.shell先后使用fork和exec系统调用来执行一个外部命令. 2.在linux系统中,有三个文件会被内核自动打开,分别是stdin.stdout.stderr. 3.进程的属性相关命令: 查看 ...