关闭

Android网络编程之使用HttpClient批量上传文件(一)

标签: MultipartEntityBuildAndroid网络编程之使用HttpClAndroid使用HttpClient上
13988人阅读 评论(17) 收藏 举报
分类:

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


我曾在《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方法直接可以添加FileInputStreambyte[]类型的数据。

2.通过addPart方法只能添加ContentBody类型的数据,在org.apache.http.entity.mime.content包中已经提供了StringFile以及InputStream对应的ContentBody类型的子类,如FileBodyInputStreamBodyStringBody通过这些类我们可以将StringFile以及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.0API,主要用到的方法有:

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都是些参数,而不是要保存的文件了。


程序运行效果图:


Android使用HttpClient上传数据

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;		
	}
}



19
1
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

轻松把玩HttpClient之封装HttpClient工具类(九),添加多文件上传功能

在Git上有人给我提Issue,说怎么上传文件,其实我一开始就想上这个功能,不过这半年比较忙,所以一直耽搁了。这次正好没什么任务了,赶紧完成这个功能。毕竟作为一款工具类,有基本的请求和下载功能,就差上传了,有点说不过去。好了,天不早了,咱干点正事吧。      ...
  • xiaoxian8023
  • xiaoxian8023
  • 2016-11-07 14:13
  • 4541

android批量文件上传(android批量图片上传)

项目中多处用到文件批量上传功能,今天正好解决了此问题,在此写出来,以便日后借鉴。 首先,以下架构下的批量文件上传可能会失败或者不会成功:             1.android客户端+springMVC服务端:服务端采用org.sp...
  • y150481863
  • y150481863
  • 2014-05-07 12:10
  • 62661

Android批量上传文件

  • u010785585
  • u010785585
  • 2015-08-27 09:34
  • 1028

android批量文件上传(android批量图片上传)

在百度完所有的的批量上传文件或图片无果之后。要么写的太渣、要么写的太乱,反正没让我看懂,最终决定进下心来自己写........ 有这么一个需求,“我要上传姓名、身份证号、机构代码、身份证照片、营业执照、组织机构图” 其实很简单用MultipartEntity类就可以完成数据的传送, 我最开始用的...
  • u012123938
  • u012123938
  • 2015-11-19 22:23
  • 2324

Android网络开源库-Retrofit(三) 批量上传及上传进度监听

由于gif图太大的原因,我将图放在了github,如果博客中显示不出来图,传送门 由于我是事先写在md上的,导致代码的可读性差,大家将就着看吧。 1. 前言在上一篇博客中,我们介绍了Retrofit的文件上传,文件下载以及进度监听,这篇博客我们来了解下批量上传以及上传进度的监听。2.批量上传要想实现...
  • qq_21430549
  • qq_21430549
  • 2016-04-23 18:32
  • 10067

Android客户端多文件上传

在web开发中,多文件上传时是非常方便的,直接使用Http协议提交数据即可。格式如下: 但是在Android客户端中,如果文本和文件一起上传时就比较麻烦,需要对Http...
  • zhegemingzihaonan
  • zhegemingzihaonan
  • 2016-05-06 20:51
  • 1312

Android 批量上传图片进度回调

之前写过一个对图片进行高保真压缩的文章,把图片压缩的这么小当然是为了上传的,这次就把图片批量上传的代码也一起贴出来,这个方法是基于xUtils的Http模块 首先这个上传过程要满足一下特性 1、开启多个线程进行图片的批量同时上传 2、每张图片的上传进度都可以获取到,并且显示在界面上 3、如果...
  • lvshaorong
  • lvshaorong
  • 2016-04-27 19:56
  • 5782

Android 批量上传sd卡图片

最近手头上需要批量上传一些保存到SD卡图片由于简单,过于忘记,写在博客中吧!同时也希望能帮到大家! 一 、 以下是一个Service类 package cn.com.service; import java.io.File; import java.util.ArrayList; impo...
  • chonbj
  • chonbj
  • 2013-08-22 15:00
  • 8955

android 文件上传(多个或单个),图片上传

  • 2015-07-13 17:27
  • 2.39MB
  • 下载

android客户端多文件上传(最简单和强悍版本),一看就懂

多文件上传
  • xiangyihu
  • xiangyihu
  • 2016-03-15 09:44
  • 1037
    个人资料
    • 访问:983326次
    • 积分:12025
    • 等级:
    • 排名:第1436名
    • 原创:181篇
    • 转载:4篇
    • 译文:0篇
    • 评论:225条
    这里有你需要的干货!!!
    关注我,获取推送O_o
    你需要的,才是干货@开源项目
    博客专栏
    最新评论