861
技術社區[雲棲]
Android 文件的上傳和下載
Android要實現文件上傳,可以利用Socket上傳,也可以模擬Web進行上傳,但是如果是使用第一種方式上傳,嚴格的話就得使用TCP,這樣容易生成係統死掉,或者是長時間等待,如果是UDP來傳,就容易造成數據丟失,因此在這裏選擇了Web進行上傳,使用Web進行上傳是模擬的Http Post上傳數據,當然,Post上傳數據的類,在網上找了一找,方式雖然很多,但是沒有一個感覺是我所使用的,所以參照原理之類的,進行了一下修改,算是做了一個參考。並且利用這個類完成了文件和表彰的上傳服務。
具體代碼如下:
文件與表單上傳類:
package com.UpLoadFileTest;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class PostFile {
//上傳代碼,第一個參數,為要使用的URL,第二個參數,為表單內容,第三個參數為要上傳的文件,可以上傳多個文件,這根據需要頁定
public static String post(String actionUrl, Map<String, String> params,
Map<String, File> files) throws IOException {
String BOUNDARY = java.util.UUID.randomUUID().toString();
String PREFIX = "--", LINEND = "\r\n";
String MULTIPART_FROM_DATA = "multipart/form-data";
String CHARSET = "UTF-8";
URL uri = new URL(actionUrl);
HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
conn.setReadTimeout(5 * 1000);
conn.setDoInput(true);// 允許輸入
conn.setDoOutput(true);// 允許輸出
conn.setUseCaches(false);
conn.setRequestMethod("POST"); //Post方式
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Charsert", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA
+ ";boundary=" + BOUNDARY);
// 首先組拚文本類型的參數
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINEND);
sb.append("Content-Disposition: form-data; name=\""
+ entry.getKey() + "\"" + LINEND);
sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND);
sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
sb.append(LINEND);
sb.append(entry.getValue());
sb.append(LINEND);
}
DataOutputStream outStream = new DataOutputStream(conn
.getOutputStream());
outStream.write(sb.toString().getBytes());
// 發送文件數據
if (files != null)
for (Map.Entry<String, File> file : files.entrySet()) {
StringBuilder sb1 = new StringBuilder();
sb1.append(PREFIX);
sb1.append(BOUNDARY);
sb1.append(LINEND);
sb1
.append("Content-Disposition: form-data; name=\"file\"; filename=\""
+ file.getKey() + "\"" + LINEND);
sb1.append("Content-Type: application/octet-stream; charset="
+ CHARSET + LINEND);
sb1.append(LINEND);
outStream.write(sb1.toString().getBytes());
InputStream is = new FileInputStream(file.getValue());
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
is.close();
outStream.write(LINEND.getBytes());
}
// 請求結束標誌
byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
outStream.write(end_data);
outStream.flush();
// 得到響應碼
int res = conn.getResponseCode();
InputStream in = conn.getInputStream();
InputStreamReader isReader = new InputStreamReader(in);
BufferedReader bufReader = new BufferedReader(isReader);
String line = null;
String data = "OK";
while((line = bufReader.readLine())==null)
data += line;
if (res == 200) {
int ch;
StringBuilder sb2 = new StringBuilder();
while ((ch = in.read()) != -1) {
sb2.append((char) ch);
}
}
outStream.close();
conn.disconnect();
return in.toString();
}
}
以上如果要寫入(上傳)數據,這裏使用的是out.write亦可使用out.wrtebyte(content)這樣子也可以,省得在這裏轉換了,交給係統進行轉換
這個可以根據個人的需要,加上等待條等等,如果要加上等待條的話,需要使用發送消息的方式進行,這個是我所想到的,其它的方式沒有考慮好呢,有興趣的人可以自己加上去!我在這裏不再給增加了,增加的話,將在下載中添加一個下載的進度提示條。
實現內容如下:
Button btn1;
EditText view1;
EditText text1;
String SDPath = "/sdcard/";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
view1 = (EditText) findViewById(R.id.view1);
text1 = (EditText) findViewById(R.id.edit1);
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
getFile();
try {
String name=URLEncoder.encode(text1.getText().toString(),"utf-8");
Map<String, String> params = new HashMap<String, String>();
params.put("NAME", name);
Map<String, File> files = new HashMap<String, File>();
files.put(getFile(), new File("/sdcard/"+getFile()));
view1.setText(PostFile.post("https://wdsl.recordinfo.tk/default.aspx", params, files));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
String getFile() {
File file = new File(SDPath);
File[] files = file.listFiles(new fileFilter());
String filename = "";
for (File file1 : files) {
filename = file1.getName();
}
Toast.makeText(this, filename, Toast.LENGTH_LONG).show();
return filename;
}
class fileFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String filename) {
// TODO Auto-generated method stub
return filename.endsWith(".gif");
}
}
其實下載文件與打開網頁是一樣的,打開網頁是將內容顯示出來,保存文件就是保存到文件中即可。
實現的代碼基本如下:
public void downFile(String url, String path, String fileName)
throws IOException {
if (fileName == null || fileName == "")
this.FileName = url.substring(url.lastIndexOf("/") + 1);
else
this.FileName = fileName; // 取得文件名,如果輸入新文件名,則使用新文件名
URL Url = new URL(url);
URLConnection conn = Url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
this.fileSize = conn.getContentLength();// 根據響應獲取文件大小
if (this.fileSize <= 0) { // 獲取內容長度為0
throw new RuntimeException("無法獲知文件大小 ");
}
if (is == null) { // 沒有下載流
sendMsg(Down_ERROR);
throw new RuntimeException("無法獲取文件");
}
FileOutputStream FOS = new FileOutputStream(path + this.FileName); // 創建寫入文件內存流,通過此流向目標寫文件
byte buf[] = new byte[1024];
downLoadFilePosition = 0;
int numread;
while ((numread = is.read(buf)) != -1) {
FOS.write(buf, 0, numread);
downLoadFilePosition += numread
}
try {
is.close();
} catch (Exception ex) {
;
}
}
通過此代碼就可以實現將內容保存到SD卡等設備上,當然要使用網絡,必須得有網絡的訪問權限。這個需要自己添加,在這裏不再添加!
上麵的代碼沒有實現進度條功能,如果要實現進度條功能,我現在考慮到的就是使用消息進行發送提示,首先實現一個消息。
private Handler downloadHandler = new Handler() { // 用於接收消息,處理進度條
@Override
public void handleMessage(Message msg) { // 接收到的消息,並且對接收到的消息進行處理
if (!Thread.currentThread().isInterrupted()) {
switch (msg.what) {
case DOWN_START:
pb.setMax(fileSize); //設置開始長度
case DOWN_POSITION:
pb.setProgress(downLoadFilePosition); // 設置進度
break;
case DOWN_COMPLETE:
Toast.makeText(DownLoadFileTest.this, "下載完成!", 1).show(); // 完成提示
break;
case Down_ERROR:
String error = msg.getData().getString("下載出錯!");
Toast.makeText(DownLoadFileTest.this, error, 1).show();
break;
}
}
super.handleMessage(msg);
}
};
最後更新:2017-04-04 07:03:45