最近项目中要用优化文件上传操作,因此对Android端文件上传做下总结。测试服务器端就用PHP写了,比较简单,代码如下:
[php] view
plaincopy
<?php
$base_path = “./uploads/”; //接收文件目录
$target_path = $base_path . basename ( $_FILES [‘uploadfile’] [‘name’] );
if (move_uploaded_file ( $_FILES [‘uploadfile’] [‘tmp_name’], $target_path )) {
$array = array (“code” => “1”, “message” => $_FILES [‘uploadfile’] [‘name’] );
echo json_encode ( $array );
} else {
$array = array (“code” => “0”, “message” => “There was an error uploading the file, please try again!” . $_FILES [‘uploadfile’] [‘error’] );
echo json_encode ( $array );
}
?>
我主要写了三种上传:人造POST请求、httpclient4(需要httpmime-4.1.3.jar)、AsyncHttpClient(对appache的HttpClient进行了进一步封装,了解更多…),当然为了并列起来看比较方便,前两种上传我直接写在主线程了,不知道对速度测试有没有影响,老鸟看到请给予批评指正,嘿嘿,下面上代码:
[java] view
plaincopy
package com.example.fileupload;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
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.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
/**
*
* ClassName:UploadActivity Function: TODO 测试上传文件,PHP服务器端接收 Reason: TODO ADD
* REASON
*
* @author Jerome Song
* @version
* @since Ver 1.1
* @Date 2013 2013-4-20 上午8:53:44
*
* @see
*/
public class UploadActivity extends Activity implements OnClickListener {
private final String TAG = “UploadActivity”;
private static final String path = “/mnt/sdcard/Desert.jpg”;
private String uploadUrl = “http://192.168.1.102:8080/Android/testupload.php“;
private Button btnAsync, btnHttpClient, btnCommonPost;
private AsyncHttpClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload);
initView();
client = new AsyncHttpClient();
}
private void initView() {
btnCommonPost = (Button) findViewById(R.id.button1);
btnHttpClient = (Button) findViewById(R.id.button2);
btnAsync = (Button) findViewById(R.id.button3);
btnCommonPost.setOnClickListener(this);
btnHttpClient.setOnClickListener(this);
btnAsync.setOnClickListener(this);
}
@Override
public void onClick(View v) {
long startTime = System.currentTimeMillis();
String tag = null;
try {
switch (v.getId()) {
case R.id.button1:
upLoadByCommonPost();
tag = “CommonPost====>”;
break;
case R.id.button2:
upLoadByHttpClient4();
tag = “HttpClient====>”;
break;
case R.id.button3:
upLoadByAsyncHttpClient();
tag = “AsyncHttpClient====>”;
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG, tag + “wasteTime = “
+ (System.currentTimeMillis() – startTime));
}
/**
* upLoadByAsyncHttpClient:由人造post上传
*
* @return void
* @throws IOException
* @throws
* @since CodingExample Ver 1.1
*/
private void upLoadByCommonPost() throws IOException {
String end = “\r\n”;
String twoHyphens = “–“;
String boundary = “******”;
URL url = new URL(uploadUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
httpURLConnection.setChunkedStreamingMode(128 * 1024);// 128K
// 允许输入输出流
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
// 使用POST方法
httpURLConnection.setRequestMethod(“POST”);
httpURLConnection.setRequestProperty(“Connection”, “Keep-Alive”);
httpURLConnection.setRequestProperty(“Charset”, “UTF-8”);
httpURLConnection.setRequestProperty(“Content-Type”,
“multipart/form-data;boundary=” + boundary);
DataOutputStream dos = new DataOutputStream(
httpURLConnection.getOutputStream());
dos.writeBytes(twoHyphens + boundary + end);
dos.writeBytes(“Content-Disposition: form-data; name=\”uploadfile\”; filename=\””
+ path.substring(path.lastIndexOf(“/”) + 1) + “\”” + end);
dos.writeBytes(end);
FileInputStream fis = new FileInputStream(path);
byte[] buffer = new byte[8192]; // 8k
int count = 0;
// 读取文件
while ((count = fis.read(buffer)) != –1) {
dos.write(buffer, 0, count);
}
fis.close();
dos.writeBytes(end);
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
dos.flush();
InputStream is = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is, “utf-8”);
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
Log.i(TAG, result);
dos.close();
is.close();
}
/**
* upLoadByAsyncHttpClient:由HttpClient4上传
*
* @return void
* @throws IOException
* @throws ClientProtocolException
* @throws
* @since CodingExample Ver 1.1
*/
private void upLoadByHttpClient4() throws ClientProtocolException,
IOException {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(
CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost(uploadUrl);
File file = new File(path);
MultipartEntity entity = new MultipartEntity();
FileBody fileBody = new FileBody(file);
entity.addPart(“uploadfile”, fileBody);
httppost.setEntity(entity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
Log.i(TAG, EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
/**
* upLoadByAsyncHttpClient:由AsyncHttpClient框架上传
*
* @return void
* @throws FileNotFoundException
* @throws
* @since CodingExample Ver 1.1
*/
private void upLoadByAsyncHttpClient() throws FileNotFoundException {
RequestParams params = new RequestParams();
params.put(“uploadfile”, new File(path));
client.post(uploadUrl, params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, String arg1) {
super.onSuccess(arg0, arg1);
Log.i(TAG, arg1);
}
});
}
}
Andriod被我们熟知的上传就是由appache提供给的httpclient4了,毕竟比较简单,腾讯微博什么的sdk也都是这么做的,大家可以参考:
[java] view
plaincopy
/**
* Post方法传送文件和消息
*
* @param url 连接的URL
* @param queryString 请求参数串
* @param files 上传的文件列表
* @return 服务器返回的信息
* @throws Exception
*/
public String httpPostWithFile(String url, String queryString, List<NameValuePair> files) throws Exception {
String responseData = null;
URI tmpUri=new URI(url);
URI uri = URIUtils.createURI(tmpUri.getScheme(), tmpUri.getHost(), tmpUri.getPort(), tmpUri.getPath(),
queryString, null);
Log.i(TAG, “QHttpClient httpPostWithFile [1] uri = “+uri.toURL());
MultipartEntity mpEntity = new MultipartEntity();
HttpPost httpPost = new HttpPost(uri);
StringBody stringBody;
FileBody fileBody;
File targetFile;
String filePath;
FormBodyPart fbp;
List<NameValuePair> queryParamList=QStrOperate.getQueryParamsList(queryString);
for(NameValuePair queryParam:queryParamList){
stringBody=new StringBody(queryParam.getValue(),Charset.forName(“UTF-8”));
fbp= new FormBodyPart(queryParam.getName(), stringBody);
mpEntity.addPart(fbp);
// Log.i(TAG, “——- “+queryParam.getName()+” = “+queryParam.getValue());
}
for (NameValuePair param : files) {
filePath = param.getValue();
targetFile= new File(filePath);
fileBody = new FileBody(targetFile,“application/octet-stream”);
fbp= new FormBodyPart(param.getName(), fileBody);
mpEntity.addPart(fbp);
}
// Log.i(TAG, “———- Entity Content Type = “+mpEntity.getContentType());
httpPost.setEntity(mpEntity);
try {
HttpResponse response=httpClient.execute(httpPost);
Log.i(TAG, “QHttpClient httpPostWithFile [2] StatusLine = “+response.getStatusLine());
responseData =EntityUtils.toString(response.getEntity());
} catch (Exception e) {
e.printStackTrace();
}finally{
httpPost.abort();
}
Log.i(TAG, “QHttpClient httpPostWithFile [3] responseData = “+responseData);
return responseData;
}
很明显,开源框架的写法最简单有效,而且为异步的,提供出Handler进行结果返回,普通人造post代码量最大,上传速度大家也可以测一下,我附一张图,我上传的图片850kb左右
总体看来,代码量最多的写法可能上传速度好点儿,asyncHttpClient的上传方式速度也很理想,主要是用起来简单。
有时可能还会有上传进度返回的需求,第一种流的读写方式应该很简单解决,后两种可能还得下点儿功夫研究研究,有兴趣的朋友可以一块儿交流研究。