android 文件上传、下载
主题脉络:
- **HttpClient与HttpUrlConnection的比较
- **HttpUrlConnection文件、请求数据上传
- **HttpUrlConnection文件下载
一.文件上传之HttpClient与HttpUrlConnection的比较:
1.Httpclient的优点:代码编写方便,apache提供封装好的api可以直接使用,不用关注xml中的格式
2.HttpClient的缺点:不同的jar包差异很大,包的依赖关系有点乱,存在中文乱码(试了几个版本的jar包,网上的解决方案都不行)
3.HttpUrlConnection的优点:java语言提供的http请求的访问类,使用起来简单粗暴,更容易了解http请求的参数组装格式,遇到问题容易定位,跟服务端可以实现很好结合
4.HttpUrlConnection的缺点:格式比较复杂,稍不注意可能会写错
二.HttpUrlConnection文件、请求数据上传
提供两种解决方案,经验证都可用:
/**
* 直接通过HTTP协议提交数据到服务器,实现表单提交功能
*
* @param actionUrl
* 上传路径
* @param params
* 请求参数 key为参数名,value为参数值
* @param file
* 上传文件
*/
public static String post(String actionUrl, Map<String, String> params,
FormFile[] files) {
try {
String BOUNDARY = "---------"
+ java.util.UUID.randomUUID().toString(); // 数据分隔线
String MULTIPART_FORM_DATA = "multipart/form-data";
URL url = new URL(actionUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);// 允许输入
conn.setDoOutput(true);// 允许输出
conn.setUseCaches(false);// 不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA
+ "; boundary=" + BOUNDARY);
StringBuilder sb = new StringBuilder();
// 上传的表单参数部分,格式请参考文章
for (Map.Entry<String, String> entry : params.entrySet()) {// 构建表单字段内容
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data; name=\""
+ entry.getKey() + "\"\r\n\r\n");
sb.append(entry.getValue());
sb.append("\r\n");
}
DataOutputStream outStream = new DataOutputStream(
conn.getOutputStream());
outStream.write(sb.toString().getBytes());// 发送表单字段数据
// 上传的文件部分,格式请参考文章
for (FormFile file : files) {
StringBuilder split = new StringBuilder();
split.append("--");
split.append(BOUNDARY);
split.append("\r\n");
split.append("Content-Disposition: form-data;name=\""
+ file.getFormname() + "\";filename=\""
+ file.getFilname() + "\"\r\n");
split.append("Content-Type: " + file.getContentType()
+ "\r\n\r\n");
outStream.write(split.toString().getBytes());
outStream.write(file.getData(), 0, file.getData().length);
outStream.write("\r\n".getBytes());
}
byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();// 数据结束标志
outStream.write(end_data);
outStream.flush();
int cah = conn.getResponseCode();
if (cah != 200)
throw new RuntimeException("请求url失败");
InputStream is = conn.getInputStream();
int ch;
StringBuilder b = new StringBuilder();
while ((ch = is.read()) != -1) {
b.append((char) ch);
}
outStream.close();
conn.disconnect();
return b.toString();
} catch (Exception e) {
LogUtil.e("http", e.getMessage(), e);
return null;
}
}
/**
* 直接通过HTTP协议提交数据到服务器,实现表单提交功能(文件以流的方式来写,每次1k)
*
* @param actionUrl
* 上传路径
* @param params
* 请求参数 key为参数名,value为参数值
* @param file
* 上传文件
*/
public static String post2(String actionUrl, Map<String, String> params,
FormFile[] files) {
try {
String BOUNDARY = "---------"
+ java.util.UUID.randomUUID().toString(); // 数据分隔线
String MULTIPART_FORM_DATA = "multipart/form-data";
URL url = new URL(actionUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);// 允许输入
conn.setDoOutput(true);// 允许输出
conn.setUseCaches(false);// 不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA
+ "; boundary=" + BOUNDARY);
StringBuilder sb = new StringBuilder();
// 上传的表单参数部分,格式请参考文章
for (Map.Entry<String, String> entry : params.entrySet()) {// 构建表单字段内容
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data; name=\""
+ entry.getKey() + "\"\r\n\r\n");
sb.append(entry.getValue());
sb.append("\r\n");
}
DataOutputStream outStream = new DataOutputStream(
conn.getOutputStream());
outStream.write(sb.toString().getBytes());// 发送表单字段数据
// 上传的文件部分,格式请参考文章
for (FormFile file : files) {
StringBuilder split = new StringBuilder();
split.append("--");
split.append(BOUNDARY);
split.append("\r\n");
split.append("Content-Disposition: form-data;name=\""
+ file.getFormname() + "\";filename=\""
+ file.getFilname() + "\"\r\n");
split.append("Content-Type: " + file.getContentType()
+ "\r\n\r\n");
outStream.write(split.toString().getBytes());
// outStream.write(file.getData(), 0, file.getData().length);
if (file.getInStream() != null) {
byte[] buffer = new byte[1024];
int len = 0;
while ((len = file.getInStream().read(buffer, 0, 1024)) != -1) {
outStream.write(buffer, 0, len);
}
file.getInStream().close();
}
outStream.write("\r\n".getBytes());
}
byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();// 数据结束标志
outStream.write(end_data);
outStream.flush();
int cah = conn.getResponseCode();
if (cah != 200)
throw new RuntimeException("请求url失败");
InputStream is = conn.getInputStream();
int ch;
StringBuilder b = new StringBuilder();
while ((ch = is.read()) != -1) {
b.append((char) ch);
}
outStream.close();
conn.disconnect();
return b.toString();
} catch (Exception e) {
LogUtil.e("http", e.getMessage(), e);
return null;
}
}
三.HttpUrlConnection实现文件下载:
/**
*
* @param urlStr
* @param sdcardPath
* @param fileName
* @return -1:文件下载出错 0:文件下载成功 1:文件已经存在
*/
public File downFile(String urlStr, String sdcardPath, String fileName, Action.One<Long> processUpdateAction) {
InputStream inputStream = null;
File resultFile = null;
try {
FileUtil fileUtils = new FileUtil();
// 对中文文件名进行utf-8转码
int lastIndex = urlStr.lastIndexOf("/");
urlStr = urlStr.substring(0, lastIndex + 1);
URL url = new URL(urlStr + URLEncoder.encode(fileName, "utf-8"));
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setRequestMethod("GET");
urlConn.setReadTimeout(50* 1000); // 缓存的最长时间
// urlConn.setDoOutput(true);// 2015-12-08 modify by zhanggang
// 4.0中设置httpCon.setDoOutput(true),将导致请求以post方式提交
// urlConn.setRequestProperty("Cookie", "ASP.NET_SessionId=" + ShareData.sessionID);
// urlConn.setRequestProperty("Accept-Encoding", "identity");
urlConn.setRequestProperty("Charset", "UTF-8");
urlConn.connect();
inputStream = urlConn.getInputStream();
int contentLength = urlConn.getContentLength();
if (inputStream != null) {
// fileUtils.setTotalLength(contentLength);
System.out.println("*********************" + urlStr);
resultFile = fileUtils.write2SDFromInput(sdcardPath, fileName, inputStream, contentLength,
processUpdateAction);
}
if (resultFile != null) {
return resultFile;
}
} catch (Exception e) {
e.printStackTrace();
return resultFile;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultFile;
}
public File write2SDFromInput(String sdcardPath, String fileName,
InputStream input, int size, Action.One<Long> processUpdateAction) {
File file = null;
File filedir = null;
OutputStream output = null;
try {
file = new File(sdcardPath.trim());
filedir = file.getParentFile();
if (!filedir.exists()) {
filedir.mkdirs(); // 正确
}
if (!file.exists()) {
file.createNewFile();
}
output = new FileOutputStream(file);
byte[] buffer = new byte[size];
int read = 0;
long readTotal = 0;
while ((read = input.read(buffer)) != -1) {
// vt.progress=(int)((step*100)/totalLength);
output.write(buffer, 0, read);
readTotal += read;
processUpdateAction.invoke((readTotal * 100) / size);
}
output.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (output != null)
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
public abstract class One<T> {
/**
* 执行方法。
*
* @param arg
* :此委托封装的方法的参数。
*/
public abstract void invoke(T arg);
}
额,第一次写,欢迎拍砖。