HTTP上传
与文件下载相比,文件上传的场合不是很多,通常用于上传用户头像、朋友圈发布图片/视频动态等等,而且上传文件需要服务器配合,所以容易被app开发者忽略。就上传的形式来说,app一般采用http上传文件,很少用ftp上传文件。HttpURLConnection上传
很可惜Android没有提供专门的文件上传工具类,所以我们要自己写代码实现上传功能了。其实也不难,一样是按照普通网络访问的POST流程,只是要采用“multipart/form-data”方式来分段传输。另外文件上传需要运用打开文件的对话框,文件对话框的介绍参见《 Android开发笔记(二十三)文件对话框FileDialog》。下面是HttpURLConnection上传文件的工具类代码:
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class UploadUtil {
private static final String TAG = "UploadUtil";
public static String upload(String uploadUrl, String uploadFile) {
String fileName = "";
int pos = uploadFile.lastIndexOf("/");
if (pos >= 0) {
fileName = uploadFile.substring(pos + 1);
}
String end = "\r\n";
String Hyphens = "--";
String boundary = "WUm4580jbtwfJhNp7zi1djFEO3wNNm";
try {
URL url = new URL(uploadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
DataOutputStream ds = new DataOutputStream(conn.getOutputStream());
ds.writeBytes(Hyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data; "
+ "name=\"file1\";filename=\"" + fileName + "\"" + end);
ds.writeBytes(end);
FileInputStream fStream = new FileInputStream(uploadFile);
// 每次写入1024字节
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int length = -1;
// 将文件数据写入到缓冲区
while((length = fStream.read(buffer)) != -1) {
ds.write(buffer, 0, length);
}
ds.writeBytes(end);
ds.writeBytes(Hyphens + boundary + Hyphens + end);
fStream.close();
ds.flush();
// 获取返回内容
InputStream is = conn.getInputStream();
int ch;
StringBuffer b = new StringBuffer();
while ((ch = is.read()) != -1) {
b.append((char) ch);
}
ds.close();
return "SUCC";
} catch (Exception e) {
e.printStackTrace();
return "上传失败:" + e.getMessage();
}
}
}
android-async-http上传
HttpURLConnection需要开发者自己拼接请求包,容易出错,并且处理单一不够灵活,因此涌现了几个开源的http框架,方便开发者进行http通信的编码。android-async-http是这其中使用较多的一个网络请求框架,它的项目地址在 https://github.com/loopj/android-async-http 。据官方介绍,android-async-http是基于Apache HttpClient库之上的一个异步网络请求处理库,网络处理均基于Android的非UI线程,通过回调方法处理请求结果。这里我们使用该库进行文件上传,主要用到AsyncHttpClient类的post方法,要上传的文件信息放在RequestParams对象中。
下面是android-async-http上传文件的工具类代码:
import java.io.File;
import com.example.exmupload.MainActivity;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.RequestParams;
import android.util.Log;
public class AsyncUtil {
private static final String TAG = "AsyncUtil";
public static String upload(final MainActivity act, String uploadServlet, String filePath, boolean isBinary) {
try {
//服务端的commons-fileupload只支持multipart/form-data方式
//application/octet-stream表示任意的二进制文件,包括图片、音频、视频、压缩文件等等
String contentType = "application/octet-stream";
//String contentType = "multipart/form-data";
RequestParams params = new RequestParams();
if (isBinary == true) {
params.put("file", new File(filePath), contentType);
} else {
params.put("file", new File(filePath));
}
Log.d(TAG, "contentType="+contentType);
AsyncHttpClient client = new AsyncHttpClient();
//AsyncHttpResponseHandle不在ui线程运行,不能直接操作ui
//如果在此处定义AsyncHttpResponseHandle对象,则运行报错:
//java.lang.IllegalArgumentException: Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead.
client.post(uploadServlet, params, act.mAsyncHandler);
return "uploadByFile";
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
// //下面代码在MainActivity.java中定义
// public AsyncHttpResponseHandler mAsyncHandler = new AsyncHttpResponseHandler() {
// @Override
// public void onSuccess(int status, Header[] headers, byte[] data) {
// String result = "文件上传成功!";
// Message msg = Message.obtain();
// msg.what = ASYNC;
// msg.obj = result;
// mHandle