最近做一个项目,其中涉及到文件的上传和下载功能,大家都知道,这个功能实现其实已经烂大街了,遂、直接从网上荡了一堆代码用,结果,发现网上的代码真是良莠不齐,不是写的不全面,就是有问题,于是自己重新整理了一番,把它们发出来,希望更多人能受用。
文件上传通过org.apache.commons.httpclient.HttpClient来实现文件上传,该jar包可以直接从网上所搜、下载。
/** * @param mContext 上下文 * @param targetUrl 文件上传地址 * @param filePath 文件路径 */public void uploadFile(final Activity mContext, String targetUrl, final String filePath) {System.out.println("targetUrl: " + targetUrl + " filePath: " + filePath);if (TextUtils.isEmpty(filePath)) {Toast.makeText(mContext, "文件不存在", Toast.LENGTH_SHORT).show();return;}final PostMethod filePost = new PostMethod(targetUrl) {//这个用来中文乱码public String getRequestCharSet() {return "UTF-8";}};try {final HttpClient client = new HttpClient();File file = new File(filePath);if (file.exists() && file.isFile()) {long fileSize = file.length();if (fileSize >= 5 * 1024 * 1024) {Toast.makeText(mContext, "文件不得大于5M", Toast.LENGTH_SHORT).show();return;}} else {Toast.makeText(mContext, "文件不存在", Toast.LENGTH_SHORT).show();return;}// 上传文件和参数Part[] parts = new Part[]{new CustomFilePart(file.getName(), file),new StringPart("filename", file.getName(), "UTF-8")};filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));new Thread(new Runnable() {@Overridepublic void run() {int statuscode = 0;try {statuscode = client.executeMethod(filePost);} catch (IOException e) {e.printStackTrace();}final int finalStatuscode = statuscode;mContext.runOnUiThread(new Runnable() {@Overridepublic void run() {if (finalStatuscode == HttpStatus.SC_OK) {Toast.makeText(mContext, "上传成功", Toast.LENGTH_SHORT).show();} else {Toast.makeText(mContext, "上传失败", Toast.LENGTH_SHORT).show();}}});}}).start();} catch (Exception ex) {ex.printStackTrace();}}
HttpClient的使用,常常会遇到乱码问题,我们主要在两个地方解决乱码问题:
•复写PostMethod 的getRequestCharSet,指定请求编码
final PostMethod filePost = new PostMethod(targetUrl) {//这个用来中文乱码public String getRequestCharSet() {return "UTF-8";}};
•自定义FilePart,指定请求参数编码
/** * 解决中文文件名乱码 */public class CustomFilePart extends FilePart {public CustomFilePart(String filename, File file)throws FileNotFoundException {super(filename, file);}protected void sendDispositionHeader(OutputStream out) throws IOException {super.sendDispositionHeader(out);String filename = getSource().getFileName();if (filename != null) {out.write(EncodingUtil.getAsciiBytes(FILE_NAME));out.write(QUOTE_BYTES);out.write(EncodingUtil.getBytes(filename, "UTF-8"));out.write(QUOTE_BYTES);}}}
使用CustomFilePart添加参数:
Part[] parts = new Part[]{new CustomFilePart(file.getName(), file),new StringPart("filename", file.getName(), "UTF-8")};filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
文件下载通过HttpURLConnection下载文件。
/** * @param urlStr文件地址 * @param path 文件保存路径 * @param fileName 文件名 * @return 文件的绝对路径 */public String downFile(String urlStr, String path, String fileName) {InputStream inputStream = null;String filePath = null;try {FileUtils fileUtils = new FileUtils();//判断文件是否存在if (fileUtils.isFileExist(path + fileName)) {System.out.println("exits");filePath = SDPATH + path + fileName;} else {//得到io流inputStream = getInputStreamFromURL(urlStr);//从input流中将文件写入SD卡中File resultFile = fileUtils.write2SDFromInput(path, fileName, inputStream);if (resultFile != null) {filePath = resultFile.getPath();}}} catch (Exception e) {e.printStackTrace();} finally {try {if (inputStream != null)inputStream.close();} catch (IOException e) {e.printStackTrace();}}return filePath;}/** * 根据URL得到输入流 * * @param urlStr * @return */public InputStream getInputStreamFromURL(String urlStr) {HttpURLConnection urlConn;InputStream inputStream = null;try {url = new URL(urlStr);urlConn = (HttpURLConnection) url.openConnection();inputStream = urlConn.getInputStream();} catch (Exception e) {e.printStackTrace();}return inputStream;}
文件下载其实很简单,说白了,就是通过HTTP获取InputStream ,然后通过解析InputStream 并写入到文件即可。
读取Inputstream并写入到SDCard。
/** * 将一个InputStream里面的数据写入到SD卡中 * * @param path 文件保存路径 * @param fileName 文件保存的名字 * @param input 文件输入流 * @return 文件 */public File write2SDFromInput(String path, String fileName, InputStream input) {File file = null;OutputStream output = null;try {// 创建文件夹createSDDir(path);// 创建文件file = createSDFile(path + fileName);// 开启输出流,准备写入文件output = new FileOutputStream(file);// 缓冲区byte[] buffer = new byte[FILESIZE];int count;while ((count = input.read(buffer)) != -1) {// 这里,请一定按该方式写入文件,不然时而会出现文件写入错误,数据丢失问题output.write(buffer, 0, count);}output.flush();} catch (Exception e) {e.printStackTrace();} finally {try {output.close();input.close();} catch (IOException e) {e.printStackTrace();}}return file;}
Inputstream写入到sdcard卡中,有个很重要的地方,先看下OutputStream 的write方法:
我推荐使用第二个方法write(byte[] b, int off, int len) ,目的是为了避免数据丢失。所以写文件代码如下:
while ((count = input.read(buffer)) != -1) { // 这里,请一定按该方式写入文件,不然时而会出现文件写入错误,数据丢失问题 output.write(buffer, 0, count);}
源码地址:https://github.com/zuiwuyuan/Http_Uploader_Downloader
以上便是我整理的Android Http实现文件的上传和下载方法,希望对更多的人有所帮助。