在android網路編程學習與實戰之旅一中,實現了把一個或者多個檔案上傳的自己搭建的伺服器中,那麼這一節,顯而易見的內容當然是怎麼把檔案下載下來。這裡依舊使用java.net包中的HttpUrlConnection來實現。關於下載後的檔案,可以有兩種處理方式,一種是把它儲存下來,另一種是把它顯示出來,比如圖片文字等可以下載後直接顯示出來。
為了更具直觀性的學習Android檔案下載,這裡首先嘗試把一個txt格式的檔案下載下來顯示在TextView中。
那麼,我想到的第一個問題是:我怎麼獲得下載檔案的檔案名稱。因為我要儲存它,我得知道它的名字。
回應標頭裡面有有檔案名稱的資訊嗎。 擷取回應標頭
首先聲明一下,這裡要下載的檔案在自己搭建的apache更目錄下的pic目錄下,是一個hello.txt檔案,它的URL是這樣的:
http://192.168.0.103:8088/pic/hello.txt
為瞭解決這兩個問題,這裡首先讀出回應標頭,也就是使用:
Map<String, List<String>> map = httpURLConnection.getHeaderFields();
這個函數就是用來擷取回應標頭的,它返回一個Map,key是一個字串,values是一個List。那麼現在把整個頭顯示出來看看它到底長什麼樣子:
上面這個小圖就是在TextView中顯示出來的回應標頭的資訊,只要獲得了它的回應標頭的這個Map,顯示應該就沒什麼問題了吧,所以這裡就不貼代碼了,最後這個方法我會一併貼出來。
仔細找來找去,也沒有找到任何關於filaname的資訊,那怎麼辦呢。因為佈建要求url的時候,裡面已經包含了filename,所以暫時從它裡面提取出來吧,大家誰有好辦法歡迎留言。提取的代碼很簡單:
int location =requesl.lastIndexOf('/'); String filename = requesl.substring(location+1);這裡的requesl就是url的字串。
擷取檔案內容
擷取檔案的內容就是讀HttpUrlConnection下getInputStream這個流了,具體怎麼讀代碼中有注釋,現在把這個方法完整的貼出來:
public static void doDownLoadFile(Handler handler){ final String requesl = "http://192.168.0.103:8088/pic/hello.txt"; URL url = null; HttpURLConnection httpURLConnection = null; try { url = new URL(requesl); //1 提取url中的檔案名稱 int location =requesl.lastIndexOf('/'); String filename = requesl.substring(location+1); //2.開啟串連 httpURLConnection = (HttpURLConnection) url.openConnection(); //3 獲得相應頭 Map<String, List<String>> map = httpURLConnection.getHeaderFields(); Set<String> keySet = map.keySet(); StringBuilder builder = new StringBuilder(); builder.append("filename : "+filename+"\n"); List<String> values ; if (keySet != null){ for (String s:keySet ) { builder.append(s+":"); values = map.get(s); for (String ss:values ) { builder.append(ss); } builder.append("\n"); } } //4. 獲得讀入流 InputStream in = httpURLConnection.getInputStream(); //4.1獲得檔案長度 int length = Integer.valueOf(map.get("Content-Length").get(0)); byte []bbb = new byte[length]; //讀出檔案 in.read(bbb); String ssss = new String(bbb); builder.append(ssss); //通知UI更新 Message message = new Message(); Bundle bundle= new Bundle(); bundle.putString("name",builder.toString()); message.setData(bundle); handler.sendMessage(message); //關閉流 in.close(); httpURLConnection.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
通過這個代碼,我們就把回應標頭和檔案內容全部顯示到TextView中了。這個函數的handler使用來通知UI更新的,在MainActivity中有一個Hanler處理訊息:
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; } });在訊息處理函數中擷取Message中的資料,把它顯示在TextView中。
效果如下:
那麼既然已經讀到了檔案的檔案的內容,那下面就把這個檔案儲存起來。 儲存檔案
那麼要把檔案儲存到哪裡呢。
assets目錄下肯定是不行的,因為它是唯讀,SD卡貌似是個不錯的選擇,但是不是所有的手機都有SD卡。那這裡就簡單的儲存在應用程式預設的檔案目錄下面吧。
public static void doSaveFileInDefaultFileDir(Context context,String filename,byte[] bb){ //1.首先判斷檔案是否存在,存在就什麼都不做,不存在就儲存它 File file = new File(context.getFilesDir(),filename); if(!file.exists()){ try { file.createNewFile(); FileOutputStream fout = new FileOutputStream(file); fout.write(bb); fout.close(); } catch (IOException e) { e.printStackTrace(); } } }
這就是我們的儲存檔案的函數,它非常簡單,首先判斷檔案是否存在,不存在就建立一個。注意,建立的時候使用的是
context.getFilesDir(),它會獲得/data/data/包名/files路勁,這個目錄是應用程式私人的目錄,應用程式又讀寫權限。
然後我們擷取到這個檔案的輸出資料流,把我們從網路上讀到的資料寫入流中,最後關閉流就可以了。
注意:為了使用context.getFilesDir()函數,這裡給這個函數加了一個Context的參數,那麼在前面doDownLoadFile方法中也需要
加入這個參數聲明。在調用doDownLoadFile方法的地方也不要忘了添加這個參數。
最後,使用adb shell命令進入手機看看檔案是不是儲存成功了。我這裡使用的是android模擬器,它可以獲得root許可權:
1.adb shell
2.su
3.cd /data/data/com.konka.networktest/files
4.ls 就會發現這個檔案已經存在了。
5.cat hello.txt看看這個檔案內容是不是完整
至此,下載與儲存檔案就做完了,下載比上傳還要簡單一點吧。