多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > [置頂] android網絡編程學習與實戰之旅一<HttpUrlConnection上傳單個或多個文件>

[置頂] android網絡編程學習與實戰之旅一<HttpUrlConnection上傳單個或多個文件>

來源:程序員人生   發布時間:2016-07-28 09:28:35 閱讀次數:2847次

1.HttpUrlConnection類概述

HttpUrlConnection是1個HTTP協議的UrlConnection,用于通過web收發數據。數據可以是任意類型和長度。這個類主要用于收發提早不知長度的數據流。

這個類的用法遵守以下模式:

  1. 首先取得1個HttpUrlConnection的實例。通過調用URL類中的openConnection()函數。并做強迫類型轉換。
  2. 準備要求。要求的基本屬性是1個URL,要求頭可能包括1些元數據,比如:證書, 首選的內容類型,session和cookie等。
  3. 可選的上傳1個要求體。HttpUrlConnection的實例如果包括1個要求體的話,必須使用setDoOutput(true)函數設置1下。然后可以通過getOutPutStream取得1個輸出流,向流中寫入數據便可傳輸數據。
  4. 讀響應。典型響應頭包括著這樣1些元數據,比如:1.響應體的內容類型和長度,2.修改的日期,3.session和cookie等。響應體可以從getInputStread()返回的流中讀取。如果響應沒有響應體,getInputStread()返回為空。
  5. 斷開連接。1旦響應體被讀取,HttpUrlConnection應當通過調用disconnect()方法來關閉。這個關閉會釋放這個連接所持有的資源。
根據上述要求,初步寫以下實驗程序,這個程序的功能就是向服務器發送1個要求,并取得服務器的響應,把這些響應顯示在1個TextView中。
<span style="font-family:SimSun;font-size:14px;">public class MainActivity extends AppCompatActivity { URL url = null; TextView textView; Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text); Log.d("hello","oncreate"); handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { Log.d("hello",msg.getData().getString("name")); textView.setText(msg.getData().getString("name")); return true; } }); new Thread(new Runnable() { HttpURLConnection connection; @Override public void run() { try { url = new URL("https://www.baidu.com/?tn=57095150_1_oem_dg"); connection = (HttpURLConnection) url.openConnection(); InputStream in = new BufferedInputStream(connection.getInputStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in)); StringBuilder stringBuilder = new StringBuilder(); String line; while ((line=bufferedReader.readLine())!=null){ stringBuilder.append(line); } Message message = new Message(); Bundle bundle= new Bundle(); bundle.putString("name",stringBuilder.toString()); message.setData(bundle); handler.sendMessage(message); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { connection.disconnect(); } } }).start(); } }</span>
這段代碼訪問https://www.baidu.com/?tn=57095150_1_oem_dg頁面,并把取得的內容放到Textview中顯示。需要注意的幾點:
  1. Android的Ui線程不可以訪問網絡等耗時的工作,所以這里將其放在1個子線程中。
  2. TextView1頁可能顯示不完,最好把TextView放到1個ScrollView中,這樣就能夠向下轉動查看所有內容了。
  3. 使用Handler可Message更新UI.
  4. 不要忘記添加網絡訪問權限:
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>

1.2.基于HTTPS安全連接

首先也是使用openConnection()方法取得1個HttpsURLConnection實例。這個URL固然是使用“https://”開頭的URL.它允許覆寫
HostnameVerifierSSLSocketFactory接口。1個支持SSLSocketFactory的利用程序可以提供1個自定義的X509TrustManager,
用于證書鏈的驗證,并且1個自定義的X509KeyManager用于客戶真個驗證。

1.3.發送內容

為了上傳數據到服務器,配置連接為輸出,使用setDoOutput(true),為了更高實現更好的額性能,是使用setFixedLengthStreamingMode(int)
設置數據長度,如果數據長度提早可以知道的話,或使用setChunkedStreamingMode(int)當不知道數據長度的時候。否則,
HttpUrlConnection將會緩沖完全的要求體,緩沖完成后才會發送,這致使了內存的浪費和延遲的增加。

2.上傳1張或多張圖片到服務器


通過以上理論知識的學習,上傳1張圖片到服務器成為可能,為了完成這個功能,首先需要解決以下問題:
解決方法是:自己搭建Apache服務器,接收使用php好了,由于php之前略有涉略,其他的Web服務器真個語言均1無所知。
上傳的文件在哪里呢?簡單起見,就是放在assets目錄下的文件。assets目錄下的文件可使用AssetManager進行管理,非常方便,為了使用assets目錄,在實現上傳文件功能之前,先做這樣1件嘗試:

2.1把assets目錄下的1張圖片顯示到ImageView中

這是很簡單的1步,為了項目的完全,還是把它貼出來,這是1個讀assets目錄下文件的方法:
<span style="font-family:SimSun;font-size:14px;"> public Bitmap readAssetsFile(String name){ Bitmap image = null; InputStream inputStream = null; try { inputStream = getResources().getAssets().open(name); image = BitmapFactory.decodeStream(inputStream); } catch (IOException e) { e.printStackTrace(); } finally { if(inputStream != null) try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return image; }</span>

2.2 php保存上傳的文件

由于我對php只是了解性的學習過,所以這部份也單獨拿出來,先把它做好,然后再往下做。這個進程分為以下幾步:
  1. 先搭建好服務器,建議直接裝wamp,這個比較簡單,然后啟動它。
  2. 使用html給上傳文件,并用php腳本接受文件,確保php可以正常工作。
  3. 編寫android端代碼并且測試。
服務器的搭建這里就不啰嗦了,啟動它也沒啥好說的,現在測試使用html上傳文件,并用php接受的代碼。
html的代碼以下:
<span style="font-family:SimSun;font-size:14px;"><!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf⑻" /> <title>file upload</title> </head> <body> <form action="http://127.0.0.1:8088/php/fileupload.php" method="post" enctype="multipart/form-data"> <input type="file" name="myfile" class="file" id="fileField" onchange="document.getElementById('textfield').value=this.value" /> <input type="submit" name="submit" value="上傳" /> </form> </body> </html></span>

這個代碼非常簡單,就是使用1個表單上傳文件。它的模樣是這樣的:


php代碼以下:
<span style="font-family:SimSun;font-size:14px;"><pre name="code" class="php"><?php echo "file arrived"; echo "Upload: ".$_FILES["myfile"]["name"]."<br />"; echo "Type: ".$_FILES["myfile"]["type"]."<br />"; echo "Size: ".($_FILES["myfile"]["size"]/1024)." Kb<br />"; echo "Temp file: " . $_FILES["myfile"]["tmp_name"]."<br />"; if (file_exists("D:/wamp/www/"."upload/" . $_FILES["myfile"]["name"])) { echo $_FILES["myfile"]["name"]." already exists. "; } else { if(move_uploaded_file($_FILES["myfile"]["tmp_name"],"D:/wamp/www/"."upload/" . $_FILES["myfile"]["name"])){ echo "Stored in: " . "upload/" . $_FILES["myfile"]["name"]; }else{ echo "Store failed"; } } ?></span>

這段代碼中,為了方便調錯,首先將上傳文件的信息都打印出來。然后 判斷這個文件在服務器的upload目錄下存在不?存在就甚么都不做,不存在就把它存儲下來。這里要注意:文件的路勁要用絕對路勁,不然會報錯,甚么緣由這里就不深究了,反正加上絕對路勁就能夠了。就這樣簡簡單單的1些代碼,就實現了文件的上傳與保存。這些代碼主要用來測試服務器端可以正常的接受并且保存文件。有了這些驗證,我們就能夠安心的專注于Android真個代碼了。
這里把這段代碼接遭到上傳文件后頁面與文件上傳到服務器的情形給個交代:

2.3android端上傳文件的代碼

在正式寫代碼之前,先回顧1下第1小節的基礎內容。通過第1小節的學習,知道了怎樣訪問1個服務器,怎樣獲得服務器的響應,怎樣發送數據塊給服務器。可以想象1下,上傳1張圖片就是把1個數據塊發送給服務器,所以這里的知識已基本具有了。但是為了更好的理解HttpUrlConnection這個類,在看看這個類的API文檔,耐心的把它看完,寫代碼是1件不用著急的事情。

2.3.1性能

為了能寫出比較好的代碼,學習如何提高性能是很有必要的。除1.3介紹的設置發送的內容的長度或明確告知不知道數據內容長度外,還需要注意甚么呢?
  1. 這個類返回的輸入輸出流是不緩沖存。大部份時候都需要把輸入輸出流包裝為緩沖流。如果是直接簡單的對大塊數據進行讀寫,也能夠疏忽緩存。
  2. 為了減少延遲,這個類可能會為多個要求/ 響應對使用相同的底層的socket。這致使http連接會保持打開狀態很長時間,所以當不要連接的時候。通過設置http.keepAlive系統屬性為false,這類行動可以被制止。使用http.maxConnections可以設置每一個連接到服務器的最大的空閑連接的數目。
  3. 默許的,這個類要求服務器的時候會使用gzip自動緊縮,并且當調用者調用getInputSream時會自動解緊縮。這類情況下,Content-Encoding 和Content-Length要被聲明,gzip緊縮可以被關閉使用以下方法:
    <span style="font-family:SimSun;font-size:14px;">urlConnection.setRequestProperty("Accept-Encoding", "identity");</span>
  4. getContentLength()可以取得傳輸的字節數,但是不能被用作獲得getInputStread中可被讀取的字節數。取而代之的是,應當使用read()方法,直到它返回⑴。表明數據讀完。

2.3.2處理登錄

1些wifi網絡阻塞用戶訪問因特網,直到用戶通過登錄頁面。這類登錄頁面典型的代表是使用http重定向。你可使用getUrl()方法可以堅持連接有無被意外的重定向。這類檢查在已接遭到響應頭以后就不可用了,這里的響應頭的獲得可使用
getHeaderFields()getInputStream()方法。比如,為了檢查1個響應有無重定向到另外1個主機,可以像以下這樣:
<span style="font-family:SimSun;font-size:14px;"> HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); try { InputStream in = new BufferedInputStream(urlConnection.getInputStream()); if (!url.getHost().equals(urlConnection.getURL().getHost())) { // we were redirected! Kick the user out to the browser to sign on? ... } finally { urlConnection.disconnect(); } }</span>

2.3.2HTTP認證

HttpUrlConnection支持HTTP基本的認證功能。使用Authenticator支持虛擬機級別的認證處理:
<span style="font-family:SimSun;font-size:14px;"> Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password.toCharArray()); }); }</span>
除非使用HTTPS,否則,這不是1種安全的用戶認證方式。特別是,用戶名,密碼,要求,響應都沒有被加密卻在網絡間傳遞。

2.4rfc1867協議

http本來不支持文件上傳,為了支持文件上傳,rfc1867協議對其做了修改,主要設計兩方面:要求頭的修改和要求體的修改。

2.4.1要求頭的修改

Content-Type由原來的
Content-Type: application/x-www-form-urlencoded
改成了:
Content-Type: multipart/form-data; boundary=------⑺d71f4234700b8
其中,mutipart/form-data;是必須的,boundary再要求體中用到,它會把要求體分成多個塊,1塊代表1塊獨立的數據,或說是文件吧。

2.4.2要求體的修改

<span style="font-family:SimSun;font-size:14px;">----------------------------⑺d71f4234700b8 Content-Disposition: form-data; name="formhash" 59329e15 ----------------------------⑺d71f4234700b8 Content-Disposition: form-data; name="isblog" ----------------------------⑺d71f4234700b8 Content-Disposition: form-data; name="fid" 104 ----------------------------⑺d71f4234700b8</span>
可以看到要求體編程了多個塊,每塊可以代表1個獨立的文件。這里的name和php中$_FILES_[name]保持1致,也和input標簽的name屬性的值保持1致。后面還可加文件名,文件長度等信息。

2.5正式寫android代碼

2.5.1上傳1個文件

android的代碼主要難點是設置http和rfc1867協議的1些參數,那現在就以下面1個完全的POST要求的格式為例,逐條配置android代碼:
<span style="font-family:SimSun;font-size:14px;">POST /upload_file/UploadFile HTTP/1.1 Accept: text/plain, */* Accept-Language: zh-cn Host: 192.168.29.65:80 Content-Type:multipart/form-data;boundary=--------------------------⑺d33a816d302b6 User-Agent: Mozilla/4.0 (compatible; OpenOffice.org) Content-Length: 424 Connection: Keep-Alive ----------------------------⑺d33a816d302b6 Content-Disposition:form-data; name="userfile1"; filename="E:\s"Content-Type: application/octet-stream abbXXXccc ----------------------------⑺d33a816d302b6 Content-Disposition: form-data; name="text1" foo ----------------------------⑺d33a816d302b6 Content-Disposition: form-data; name="password1" bar ----------------------------⑺d33a816d302b6-- </span>
下面的代碼逐條配置了上面模板中的條目,代碼中注釋有很詳細的解釋:
<span style="font-family:SimSun;font-size:14px;">package com.konka.networktest; import android.content.Context; import android.content.res.AssetManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; /** * Created by Jinwei on 2016/6/29. */ public class Utils { public static void doupLoadPic(Context context, Handler handler){ //首先設置1些常量 final String end = "\r\n"; final String twoHyphens = "--"; final String boundary = "******"; URL url = null; HttpURLConnection httpURLConnection = null; //1.創建URL,并且獲得連接 try { url = new URL("http://192.168.0.103:8088/php/fileupload.php"); httpURLConnection = (HttpURLConnection) url.openConnection(); //2.根據這個類的使用要求,要配置1些必要的參數 httpURLConnection.setChunkedStreamingMode(128 * 1024);// 128K,這個配置可以提高性能 httpURLConnection.setDoOutput(true); //允許輸出。 httpURLConnection.setDoInput(true); //允許讀入,后面我們要讀取服務器端返回的信息 httpURLConnection.setUseCaches(false); //不使用緩沖 //3.設置rfc1867要求頭 //3.1要求行設置 POST /upload_file/UploadFile HTTP/1.1 httpURLConnection.setRequestMethod("POST"); //要求行只需設置這1個參數便可 //3.2 Accept: text/plain, */* httpURLConnection.setRequestProperty("Accept","ext/plain, */*"); //3.3 Accept-Language: zh-cn httpURLConnection.setRequestProperty("Accept-Language","zh-cn"); //3.3 Host: 192.168.0.105:80 //Host 接受響應的主機,默許就是發起連接的這里,所以這里不設置 //3.4 Content-Type:multipart/form-data;boundary=--------------------------⑺d33a816d302b6 httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary); //3.5 //User-Agent: Mozilla/4.0 (compatible; OpenOffice.org) //閱讀器類型,和我們無關,不設置 //3.6 //Content-Length: 424 //數據長度,這個類不是可以收發不知長度的數據流嗎?我們不知道長度的話就不設置了。 //3/7 //Connection: Keep-Alive ----------------------------⑺d33a816d302b6 httpURLConnection.setRequestProperty("Connection","Keep-Alive");//這里要注意,keep-Alive后面的是要求體中的內容了。所以,要求頭就設置完了 //4,設置要求體 //4.1獲得輸出流 DataOutputStream dout = new DataOutputStream(httpURLConnection.getOutputStream()); //4.2 寫分隔符,先把Keep-Alive后面的事情做完 dout.writeBytes("--"+boundary+end); //4.3 Content-Disposition:form-data; dout.writeBytes("Content-Disposition:form-data;"); //4.4 name="userfile1"; dout.writeBytes("name="+"\"myfile\";"); //4.5 filename="E:\s" dout.writeBytes("filename="+"\"one.jpg\""); //注意這里以后有兩個回車換行 dout.writeBytes(end); dout.writeBytes(end); //4.6 application/octet-stream abbXXXccc,這里就是正文了,而正文需要讀文件,以下是讀文件的部份 AssetManager am = context.getAssets(); InputStream inputStream = am.open("one.jpg"); //4.7有了文件輸入流后,我們把文件讀出來,寫到http要求體中 byte[] buffer = new byte[8192]; // 8k int count = 0; while ((count = inputStream.read(buffer)) != ⑴) { dout.write(buffer, 0, count); }//這樣文件就寫完了 //我們只有1個文件,就這樣就能夠了。依照格式,文件結束還要寫入分隔符 dout.writeBytes(end+"--"+boundary+end); //這樣發送部份就做完了。 //另外,我們還希望接受返回的數據。 //1.打開讀流 BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf⑻")); StringBuilder builder = new StringBuilder(); String result; //2.開始讀入 while((result = br.readLine())!= null){ builder.append(result); } //通知UI更新 Message message = new Message(); Bundle bundle= new Bundle(); bundle.putString("name",builder.toString()); message.setData(bundle); handler.sendMessage(message); //最后做1些清算工作 br.close(); inputStream.close(); dout.close(); httpURLConnection.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } </span>
這個這個類我完全的貼出來了,這個類中的hander用于通知UI已收到了數據了。注意,這里并沒有管文件的類型,服務器端也沒有檢查文件的類型,注意1下,需要的時候把它們加上。

2.5.2上傳多個文件

只要會上傳1個文件,而且知道了上傳多個文件就是使用"--"+boundary+"/r/n"把多個文件分開,然后在分割附后添加文件的類型,文件名等信息就能夠了,以以下出添加的代碼:
<span style="font-family:SimSun;font-size:14px;"> //發送第2個文件 //boundary已寫入了,現在寫文件的類型,名字等信息 //4.3 Content-Disposition:form-data; dout.writeBytes("Content-Disposition:form-data;"); //4.4 name="userfile1"; dout.writeBytes("name="+"\"myfile1\";"); //4.5 filename="E:\s" dout.writeBytes("filename="+"\"two.jpg\""); //注意這里以后有兩個回車換行 dout.writeBytes(end); dout.writeBytes(end); //打開第2個文件的流 InputStream inputStream1 = am.open("two.jpg"); while ((count = inputStream1.read(buffer)) != ⑴) { dout.write(buffer, 0, count); }//這樣第2個文件就寫完了 inputStream1.close(); //寫入分隔符 dout.writeBytes(end+"--"+boundary+end);</span>
服務器端也只是簡單的把接受1個文件的代碼復制1份:
<span style="font-family:SimSun;font-size:14px;">//第2個文件 echo "second file arrived"; echo "Upload: ".$_FILES["myfile1"]["name"]."<br />"; echo "Type: ".$_FILES["myfile1"]["type"]."<br />"; echo "Size: ".($_FILES["myfile1"]["size"]/1024)." Kb<br />"; echo "Temp file: " . $_FILES["myfile"]["tmp_name"]."<br />"; if (file_exists("D:/wamp/www/"."upload/" . $_FILES["myfile1"]["name"])) { echo $_FILES["myfile1"]["name"]." already exists. "; } else { if(move_uploaded_file($_FILES["myfile1"]["tmp_name"],"D:/wamp/www/"."upload/" . $_FILES["myfile1"]["name"])){ echo "Stored in: " . "upload/" . $_FILES["myfile1"]["name"]; }else{ echo "Store failed"; } } </span>


圖片展現以下:
手機端收到的信息:


服務器端多了兩個文件:

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: jizz视频在线观看 | 日本www高清免费视频观看 | 日韩一级淫片 | 日韩欧美~中文字幕 | 性欧美18xx | 国产一级视频久久 | 69av视频 | 国产大象视频一区二区 | 久久www免费人成看片入口 | 亚洲日本中文字幕在线 | 欧美xxxx性特级高清 | 天堂亚洲欧美日韩一区二区 | 久久er国产精品免费观看8 | 成人免费一区二区三区在线观看 | 2021最新热播中文字幕 | 伊人操| 人成精品 | 羞羞的动漫网站 | 黑人巨大三根一起进hd | 一级做a爰片久久毛片潮喷 一级做a爰片久久毛片看看 | 磁力天堂网在线资源www | 在线亚洲成人 | 亚洲精品一区二区久久 | 国产一级淫片a视频免费观看 | 亚洲成人影院在线 | 69久久夜色精品国产69 | 波多野结衣一区二区三区高清在线 | 免费人成激情视频在线观看冫 | 国产亚洲综合一区二区在线 | 欧美精品久久 | 欧美日韩亚 | 国产免费69成人精品视频 | 一级做a爰片久久毛片欧美 一级做a爰片久久毛片人呢 | 国产精品第二页在线播放 | 日韩手机在线免费视频 | 日本一级毛片片在线播放 | 国产一区二区三区亚洲综合 | 亚洲天堂一区二区 | 四虎东方va私人影库在线观看 | 欧美日韩aa一级视频 | 国产亚洲福利精品一区 |