Android 使用HttpClient和第三方MiME文件上传类库,实现文件上传
MainActivity中定义的方法
- private void httpUpload() {
- //定义HttpClient对象
- HttpClient client = new DefaultHttpClient();
- //获得HttpPost对象
- HttpPost post = new HttpPost("http://192.168.1.106:8001/2012/upload.php");
- post.addHeader("charset", HTTP.UTF_8);
- //实例化
- MultipartEntity me = new MultipartEntity();
- try {
- me.addPart("content",new StringBody("12cccafasdfasdf"));
- me.addPart("title",new StringBody("csdnliwei"));
- me.addPart("local",new StringBody("beijing"));
- //设置流文件
- me.addPart("file", new InputStreamBody(new FileInputStream("/mnt/sdcard/test.jpg"), "image/pjpeg", "fengjie.jpg"));
- post.setEntity(me);
- //获得响应消息
- HttpResponse resp = client.execute(post);
- if(resp.getStatusLine().getStatusCode()==200){
- Toast.makeText(this, "文件上传文成!", 1).show();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
服务器端PHP程序:
- <?php
- header("Content-type:text/html;charset=utf-8");
- print_r($_FILES['file']);
- $filename = $_FILES['file']['name'];
- if(!$_FILES['file']['error']){
- if(move_uploaded_file($_FILES['file']['tmp_name'],"./upload/".$filename)){
- echo "文件上传成功";
- }else{
- echo "文件上传失败le";
- }
- }else{
- echo "文件上传错误";
- }
- ?>
就这样就ok,实现文件上传
使用 HttpClient 4 进行文件上传
1. 概述本教程我们将描述如何使用 HttpClient 4进行一次多文件上传操作 . 我们将使用 http://echo.200please.com 作为测试服务器,因为它是面向公众的,并且接受大多数类型的内容. 如果你想要深入学习并了解你可以使用 HttpClient 做到的其它很棒的事情 – 那就去看看 首要的 HttpClient 教程吧 . 2. 使用 AddPart 方法让我们开始研究研究 MultipartEntityBuilder 对象,来向一个Http实体添加成分,它在稍后将会被通过一个POST操作上传. 这是向一个 HttpEntity添加成分来表示表单的一般方法 . 示例 2.1. - 使用两个文本成分和一个文件上传一个表单 File file = new File(textFileName, ContentType.DEFAULT_BINARY); HttpPost post = new HttpPost("http://echo.200please.com"); FileBody fileBody = new FileBody(file); StringBody stringBody1 = new StringBody("Message 1", ContentType.MULTIPART_FORM_DATA); StringBody stringBody2 = new StringBody("Message 2", ContentType.MULTIPART_FORM_DATA); // MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addPart("upfile", fileBody); builder.addPart("text1", stringBody1); builder.addPart("text2", stringBody2); HttpEntity entity = builder.build(); // post.setEntity(entity); HttpResponse response = client.execute(post);
请注意我们也通过制定将会被服务器使用到的ContentType值来实例化File对象. 同样还请注意 addPart 方法有两个参数,作用就像是表单的键值对 . 除非服务器端实际需要这些值并使用了这些参数名称,它们就是有干系的,否则它们就会被简单的忽略掉. |
3. 使用 addBinaryBody 和 addTextBody 方法创建一个multipart实体更直接的方式就是使用 addBinaryBody 和 AddTextBody 方法. 这些方法服务于上传文本,文件,字符数组和 InputStream 对象. 我们用了一个简单的例子来描述如何使用它们 . 示例 3.1. - 上传一个文本和一个文本文件部分 HttpPost post = new HttpPost("http://echo.200please.com"); File file = new File(textFileName); String message = "This is a multipart post"; MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody("upfile", file, ContentType.DEFAULT_BINARY, textFileName); builder.addTextBody("text", message, ContentType.DEFAULT_BINARY); // HttpEntity entity = builder.build(); post.setEntity(entity); HttpResponse response = client.execute(post);
注意这里不需要 FileBody 和 StringBody 对象 同样重要的是,大多数服务器不会检查文本体的 ContentType , 因此 addTextBody 方法可能会忽略掉 ContentType 值 . addBinaryBody 的 API 接受一个 ContentType - 但是它也有可能从一个二进制体来创建实体,而对应名称的表单参数持有了这个文件. 如前面小节所述,如果ContentType值没有被指定,一些服务器将不会识别这个文件. |
接下来,我们将一个zip文件作为一个 InputStream 添加进来, 而图片文件将会被作为File对象被添加进来: 示例 3.2. - 上传一个Zip文件,一个图片文件和一个文本 块 HttpPost post = new HttpPost("http://echo.200please.com"); InputStream inputStream = new FileInputStream(zipFileName); File file = new File(imageFileName); String message = "This is a multipart post"; MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody ("upfile", file, ContentType.DEFAULT_BINARY, imageFileName); builder.addBinaryBody ("upstream", inputStream, ContentType.create("application/zip"), zipFileName); builder.addTextBody("text", message, ContentType.TEXT_PLAIN); // HttpEntity entity = builder.build(); post.setEntity(entity); HttpResponse response = client.execute(post);
请注意ContentType值可以被动态创建,正如上面这个针对zip文件的示例中所示 . 最后,不是所有的服务器都接受 InputStream 部分. 我们在代码的第一行实体化的服务器可以接受 . 让我们现在来看看另外一个示例, addBinaryBody直接用于一个位数组 : 示例 3.3. - 上传一个位数组和文本 HttpPost post = new HttpPost("http://echo.200please.com"); String message = "This is a multipart post"; byte[] bytes = "binary code".getBytes(); // MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody("upfile", bytes, ContentType.DEFAULT_BINARY, textFileName); builder.addTextBody("text", message, ContentType.TEXT_PLAIN); // HttpEntity entity = builder.build(); post.setEntity(entity); HttpResponse response = client.execute(post);
留意 ContentType - 它现在被指定为二进制数据. 4. 总结本文呈现了 MultipartEntityBuilder 作为一个灵活的对象提供了创建一个 multipart 表单多种API. 示例同样也展示了如何使用HttpClient上传一个类似于表单实体的HttpEntity . 这些示例的所有实现和代码块在 我的github项目 中可以找到 – 这是一个基于Eclipse的项目, 因此可以很容易的导入并运行. |
HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议(CV大法来自于HttpClient百度百科,- -),httpclient的jar包可去apache官网或者csdn或者iask下载(个人感觉iask还是不错的,至少好多资源免积分,而且里面还有很多意想不到的资源哦, - -)。
言归正传,介绍项目中使用的httpmime-4.1.3.jar包使用,理解jar包里面的类定义及属性方法可参照其javadoc,下面直接上代码。
- public class HttpworkTask extends Thread {
- public final static String TAG = "HttpworkTask"; //log tag
- private NetworkListener listener;
- private static HttpClient httpClient;
- private final static int CONNECTIONTIMEOUT = 10000;//http链接超时
- private final static int REQUESTTIMEOUT = 20000;//http数据请求超时
- private String url = null;
- private Map<String, Object> paras = null;//post的StringBody
- private Map<String, File> fileParas = null;//post的FileBody
- public HttpworkTask(String url, Map<String, Object> paras, Map<String, File> fileParas){
- this.url = url;
- this.paras = paras;
- this.fileParas = fileParas;
- }
- @Override
- public void run() {
- BufferedReader br = null;
- StringBuilder sBuilder = new StringBuilder();
- HttpParams httpParams = new BasicHttpParams();
- HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTIONTIMEOUT);
- HttpConnectionParams.setSoTimeout(httpParams, REQUESTTIMEOUT);
- SchemeRegistry registry = new SchemeRegistry();
- registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
- //由于是使用线程操作http,所以设置Thread safe属性,不然当start多个httpworktask线程时必然报错,这点需要注意
- httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(httpParams, registry), httpParams); HttpPost post = new HttpPost(url);
- //添加 post的String 和File数据
- MultipartEntity entity = new MultipartEntity();
- try {
- // 添加参数
- if (paras != null && !paras.isEmpty()) {
- for (Map.Entry<String, Object> item : paras.entrySet()) {
- entity.addPart(item.getKey(), new StringBody(item.getValue().toString(), Charset.forName("UTF-8")));
- }
- }
- // 添加文件
- if (fileParas != null && !fileParas.isEmpty()) {
- for (Map.Entry<String, File> item : fileParas.entrySet()) {
- if (item.getValue().exists()) {
- Log.i(TAG, "upload File is exists and filepath is-->" + item.getKey() + " " + item.getValue().getPath());
- entity.addPart(item.getKey(), new FileBody(item.getValue()));
- }else{
- Log.e(TAG, "upload File is NOT exists!");
- }
- }
- }
- post.setEntity(entity);
- HttpResponse response = httpClient.execute(post);
- int statecode = response.getStatusLine().getStatusCode();
- Log.i(TAG, "http response code-->" + statecode);
- if (statecode == HttpStatus.SC_OK) {
- HttpEntity responseEntity = response.getEntity();
- if (responseEntity != null) {
- InputStream is = responseEntity.getContent();
- br = new BufferedReader(new InputStreamReader(is));
- String tempStr;
- while ((tempStr = br.readLine()) != null) {
- sBuilder.append(tempStr);
- }
- br.close();
- }
- }
- } catch (Exception e) {
- listener.onConnectionError(NetworkListener.NET_ERROR, "http connect is error,pls check your phone network");
- } finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- post.abort();
- //http返回的数据
- String resData = sBuilder.toString();
- Log.i(TAG, "http server response -->" + resData);
- if (resData != null) {
- listener.onConnectionRecieveData(resData.getBytes(), resData.length());
- }
- }
- public static void shutdownHttp() {
- if (httpClient != null) {
- httpClient.getConnectionManager().shutdown();
- }
- }
- }
- 说明几点:1.使用MultipartEntity,Stringbody和FileBody可同时post。
- 2.可同时上传n个File文件。
- 一般在定义http业务的json协议时,如json上传照片文件,imgUrls:图片文件(同时上传多张图片),entity.addPart的第一个参数为fileParas map的key值应为imgUrls,这样多次addpart后会不会顶掉前面add的