本文介绍的基于Http协议的文件上传方法,Http协议文件上传的功能是通过RFC1867规范描述的,Chrome,IE,Mozila和Opera等浏览器都支持此功能。
这里我先介绍一个工具名字叫Fiddler,它是一个Web Debugger工具,我们这里用它去分析Http 上传文件的原始内容 ,格式如下:
POST http://192.168.1.100/Handler1.ashx HTTP/1.1
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: 192.168.1.100
Content-Length: 263827
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="QQ截图20140818223203.png"
Content-Type: image/png
Android利用Http协议上传文件也必须要遵循这个规范。所以我们代码的核心就是如何用代码实现这个规范,从而实现文件的上传,上面说了一些废话。
下面进入主题
首先 要说明的一点是 由于上传是需要访问网络的,
所以一定要在AndroidManifest.xml 文件中添加访问网络的权限,如下所示:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
package com.example.imageupload.network; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.UUID; import java.io.File; public class UpFile { public static int post(String actionUrl, File file) throws IOException { //产生随机分隔内容 String BOUNDARY = UUID.randomUUID().toString(); String PREFIX = "--"; String LINEND = "\r\n"; String MULTIPART_FROM_DATA = "multipart/form-data"; String CHARSET = "UTF-8"; URL url = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //设置超时时间单位是毫秒 conn.setReadTimeout(5 * 1000); //设置允许输入 conn.setDoInput(true); //设置允许输出 conn.setDoOutput(true); //不允许使用缓存 conn.setUseCaches(false); //设置请求的方法为Post conn.setRequestMethod("POST"); //设置维持长连接 conn.setRequestProperty("Connection", "keep-alive"); //设置字符集为UTF-8 conn.setRequestProperty("Charset", CHARSET); //设置文件的类型 conn.setRequestProperty("Content-type", MULTIPART_FROM_DATA + "; boundary=" + BOUNDARY); DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); //发送文件数据 if (file != null) { StringBuilder sb = new StringBuilder(); sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINEND); sb.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + LINEND); sb.append("Content-Type: image/png" + LINEND); sb.append(LINEND); //写入输出流中 outStream.write(sb.toString().getBytes()); //将文件读入输入流中 InputStream is = new FileInputStream(file); byte[] buffer = new byte[1024]; int len = -1; //写入输出流中 while ((len = is.read(buffer)) != -1) { outStream.write(buffer, 0, len); } is.close(); //添加换行标识 outStream.write(LINEND.getBytes()); } byte[] endData = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); outStream.write(endData); //发送数据 outStream.flush(); //获取响应码 上传成功返回的是200 int res = conn.getResponseCode(); return res; } }
还有说明的一点是,网络的操作一定要在子线程里完成, 否则会产生异常
代码如下:
class Task extends AsyncTask<String, Integer, Integer> { @Override protected Integer doInBackground(String... strings) { Integer result = -1; try { result = UpFile.post("http://192.168.1.100/Handler1.ashx", new File(strings[0])); } catch (IOException e) { e.printStackTrace(); } // result = UploadFile.upLoadFile("http://192.168.1.100/Handler1.ashx", // new File(strings[0])); return result; } @Override protected void onPostExecute(Integer result) { Toast.makeText(MainActivity.this, "" + result, Toast.LENGTH_LONG).show(); } }