最近項目中要用優化文件上傳操作,因此對Android端文件上傳做下總結。測試服務器端就用PHP寫了,比較簡單,代碼如下:
- <?php
- $base_path = "./uploads/"; //<strong>接收</strong><strong>文件</strong>目錄
- $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進行了進一步封裝,瞭解更多...),當然爲了並列起來看比較方便,前兩種上傳我直接寫在主線程了,不知道對速度測試有沒有影響,老鳥看到請給予批評指正,嘿嘿,下面上代碼:
- 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 測試上傳<strong>文件</strong>,PHP服務器端<strong>接收</strong> 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;
- // 讀取<strong>文件</strong>
- 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也都是這麼做的,大家可以參考:
- /**
- * Post方法傳送<strong>文件</strong>和消息
- *
- * @param url 連接的URL
- * @param queryString 請求參數串
- * @param files 上傳的<strong>文件</strong>列表
- * @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的上傳方式速度也很理想,主要是用起來簡單。
有時可能還會有上傳進度返回的需求,第一種流的讀寫方式應該很簡單解決,後兩種可能還得下點兒功夫研究研究,有興趣的朋友可以一塊兒交流研究。