Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android使用HttpURLConnection實現帶參數文件上傳

android使用HttpURLConnection實現帶參數文件上傳

編輯:關於Android編程

文件上傳是常見功能,然而android網上大多數的文件上傳都使用httpclient,而且需要添加一個httpmine-jar,其實HttpURLConnection也可以實現文件上傳,但是它在移動端有個弊端,就是不能上傳大文件,所以這次說的方式,只能上傳一些較小的文件。

文件上傳,並且帶上一些參數,這需要我們了解http請求的構造方式,也就是它的格式。

HttpURLConnection需要我們自己構造請求頭部,也就是我們要拼接出一個正確完整的請求。

下面來看一個典型的例子

 

POST /api/feed/ HTTP/1.1
Accept-Encoding: gzip
Content-Length: 225873
Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Host: www.myhost.com
Connection: Keep-Alive

--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=param1
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

888
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=param2
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

nihao
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=images; filename=/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary

這裡是圖片的二進制數據
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp--

上面的例子中,我們首先看
POST /api/feed/ HTTP/1.1
Accept-Encoding: gzip
Content-Length: 225873
Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Host: www.myhost.com
Connection: Keep-Alive

第一行:為POST方式,要請求的子路徑為/api/feed/,例如我們的服務器地址為www.myhost.com,然後我們的這個請求的完整路徑就是www.myhost.com/api/feed/,最後說明了HTTP協議的版本號為1.1

 

第二行:數據壓縮方式

第三行:數據長度

第四行:multipart/form-data;是指上傳的數據類型,這裡是指文件形式。boundary是我們必須指定的一個分界符,不同參數之間要用這個分界符隔開。而OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp就是具體的分界符,這個參數我們可以自己隨機生成的。

第五行:主機地址

第六行:持久連接,Keep-Alive功能避免了建立或者重新建立連接

第七行:換行,這個換行是必須的,我們使用 來進行換行

 

然後就是參數內容部分了,先來看

--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=param1
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

888
我們把上面的看成一個整體

 

第一行:我要先用分隔符來聲明一個參數的開始。注意,分隔符前面還加了兩橫“--”,這個也是必須加上的!

第二行:name=param1,其實param1就是傳遞的參數的鍵值,例如在get方式中,我們這樣寫http://www.baidu.com?param1=888

第三行:同樣是內容格式,不過這次是指定傳文本,所以是text/plain; 另外,指定了編碼方式charset=UTF-8

第四行:描述的是消息請求(request)和響應(response)所附帶的實體對象(entity)的傳輸形式,簡單文本數據我們設置為8bit,文件參數我們設置為binary就行

第五行:換行,這個是必須的!

第六行:參數值,例如http://www.baidu.com?param1=888,就是888

 

OK,我們看下一個參數,也是同理

--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=param2
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

nihao

然後下一個參數,就是文件了

雖然指定的內容不一樣,但是格式是一樣的

--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=images; filename=/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary

這裡是圖片的二進制數據
--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp--

 

OK,大家仔細看上面的格式,不能出一點差錯,因為格式不對,就上傳不了了。

 

接下來,我們直接看我寫的一個帶參數文件上傳工具類

 

/**
 * Created by kaiyi.cky on 2015/8/16.
 */
public class FileUploader {
    private static final String TAG = uploadFile;
    private static final int TIME_OUT = 10*10000000; //超時時間
    private static final String CHARSET = utf-8; //設置編碼
    private static final String PREFIX = --;
    private static final String LINE_END = 
;

    public static void upload(String host,File file,Map params,FileUploadListener listener){
        String BOUNDARY = UUID.randomUUID().toString(); //邊界標識 隨機生成 String PREFIX = -- , LINE_END = 
;
        String CONTENT_TYPE = multipart/form-data; //內容類型
        try {
            URL url = new URL(host);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(TIME_OUT);
            conn.setConnectTimeout(TIME_OUT);
            conn.setRequestMethod(POST); //請求方式
            conn.setRequestProperty(Charset, CHARSET);//設置編碼
            conn.setRequestProperty(connection, keep-alive);
            conn.setRequestProperty(Content-Type, CONTENT_TYPE + ;boundary= + BOUNDARY);
            conn.setDoInput(true); //允許輸入流
            conn.setDoOutput(true); //允許輸出流
            conn.setUseCaches(false); //不允許使用緩存
            if(file!=null) {
                /** * 當文件不為空,把文件包裝並且上傳 */
                OutputStream outputSteam=conn.getOutputStream();
                DataOutputStream dos = new DataOutputStream(outputSteam);
                StringBuffer sb = new StringBuffer();
                sb.append(LINE_END);
                if(params!=null){//根據格式,開始拼接文本參數
                    for(Map.Entry entry:params.entrySet()){                        
                        sb.append(PREFIX).append(BOUNDARY).append(LINE_END);//分界符
                        sb.append(Content-Disposition: form-data; name= + entry.getKey() +  + LINE_END);
                        sb.append(Content-Type: text/plain; charset= + CHARSET + LINE_END);
                        sb.append(Content-Transfer-Encoding: 8bit + LINE_END);
                        sb.append(LINE_END);
                        sb.append(entry.getValue());
                        sb.append(LINE_END);//換行!
                    }
                }
                sb.append(PREFIX);//開始拼接文件參數
                sb.append(BOUNDARY); sb.append(LINE_END);
                /**
                 * 這裡重點注意:
                 * name裡面的值為服務器端需要key 只有這個key 才可以得到對應的文件
                 * filename是文件的名字,包含後綴名的 比如:abc.png
                 */
                sb.append(Content-Disposition: form-data; name=img; filename=+file.getName()++LINE_END);
                sb.append(Content-Type: application/octet-stream; charset=+CHARSET+LINE_END);
                sb.append(LINE_END);
                //寫入文件數據
                dos.write(sb.toString().getBytes());
                InputStream is = new FileInputStream(file);
                byte[] bytes = new byte[1024];
                long totalbytes = file.length();
                long curbytes = 0;
                Log.i(cky,total=+totalbytes);
                int len = 0;
                while((len=is.read(bytes))!=-1){
                    curbytes += len;
                    dos.write(bytes, 0, len);
                    listener.onProgress(curbytes,1.0d*curbytes/totalbytes);
                }
                is.close();
                dos.write(LINE_END.getBytes());\一定還有換行
                byte[] end_data = (PREFIX+BOUNDARY+PREFIX+LINE_END).getBytes();
                dos.write(end_data);
                dos.flush();
                /**
                 * 獲取響應碼 200=成功
                 * 當響應成功,獲取響應的流
                 */
                int code = conn.getResponseCode();
                sb.setLength(0);
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while((line=br.readLine())!=null){
                    sb.append(line);
                }
                listener.onFinish(code,sb.toString(),conn.getHeaderFields());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public interface FileUploadListener{
        public void onProgress(long pro,double precent);
        public void onFinish(int code,String res,Map> headers);
    }
}

使用方式是這樣的:

 

 

public class MainActivity extends FragmentActivity {
   
    File sdDir;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState()
                .equals(Environment.MEDIA_MOUNTED);   //判斷sd卡是否存在
        if(sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();//獲取跟目錄
        }
        final HashMap map = new HashMap();
        map.put(aa,bb);
        new Thread(){
            @Override
            public void run() {
                FileUploader.upload(上傳地址, new File(sdDir.getPath() + /文件名), map, new FileUploader.FileUploadListener() {
                    @Override
                    public void onProgress(long pro, double precent) {
                        Log.i(cky, precent+);
                    }

                    @Override
                    public void onFinish(int code, String res, Map> headers) {
                        Log.i(cky, res);
                    }
                });
            }
        }.start();        
    }   
}


 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved