Android从网络上下载文件
2015-08-27 11:10
543 查看
现在网络上关于Android下载的代码很多,但是光看还是无法完全理解和掌握,所以决定自己手写一个,以加深学习。
在写下载代码之前,有几点知识必须要掌握:
1.Http请求报文格式及响应报文,可以通过使用wireshark来对报文进行抓取,查看http协议的报文
2.HttpUrlConnection的使用
3.RandomAccessFile类的使用(可断点下载)
这里写的下载是关于断点下载的。
断点下载的原理就是在请求报文中加入Range:bytes=x-y 其中x表示开始下载的位置,y表示下载到的位置,y可省略,表示到文件结尾。例如:0- 表示从文件的开头一直读到结尾。
多线程下载页是基于这个原理。例如有三个线程。文件大小为600;则:
线程1:Range:bytes=0-199;
线程2:Range:bytes=200-399;
线程3:Range:bytes=400-
建立起连接之后,获取输入流:
在写下载代码之前,有几点知识必须要掌握:
1.Http请求报文格式及响应报文,可以通过使用wireshark来对报文进行抓取,查看http协议的报文
2.HttpUrlConnection的使用
3.RandomAccessFile类的使用(可断点下载)
这里写的下载是关于断点下载的。
断点下载的原理就是在请求报文中加入Range:bytes=x-y 其中x表示开始下载的位置,y表示下载到的位置,y可省略,表示到文件结尾。例如:0- 表示从文件的开头一直读到结尾。
多线程下载页是基于这个原理。例如有三个线程。文件大小为600;则:
线程1:Range:bytes=0-199;
线程2:Range:bytes=200-399;
线程3:Range:bytes=400-
建立起连接之后,获取输入流:
in=con.getInputStream();然后利用RandomAccessFile类就行写出。这个类可以随机写入文件,通过seek方法定位到要写的位置,然后通过write方法进行写出。代码如下
public class DownLoadUtil { private static DownLoadUtil downLoadUtil; private int readTimeOut = 6 * 1000;// 读取超时时间 private int connectTimeOut = 6 * 1000;// 连接超时时间 private OnDownLoadListener listener;// 下载监听器 private Handler handler;// 监听结果交由主线程处理 private boolean isDownloading;// 下载状态 private int downloadLength = 0;// 记录下载长度(应用中应保存在数据库中) private String requestUrl; private String path; // private Handler handerl; private DownLoadUtil() { // 获取主线程handler,可以让回调函数在主线程运行(volley框架就是通过这种方式让处理结果在主线程运行的) handler = new Handler(Looper.getMainLooper()); } public static DownLoadUtil getInstance() { if (downLoadUtil == null) { downLoadUtil = new DownLoadUtil(); } return downLoadUtil; } public void downLoad(String requestUrl, String path, int downloadLength) { this.isDownloading = true; this.requestUrl = requestUrl; this.path = path; new DownLoadThread(requestUrl, path, downloadLength).start(); } // 下载线程 public class DownLoadThread extends Thread { private String downloadUrl;// 下载地址 private String path;// 存储路径 private int downloadLength;// 已下载长度 private int progressNotifyCount;// 每下载100字节更新一次 public DownLoadThread(String downloadUrl, String path, int downloadLength) { this.downloadLength = downloadLength; this.path = path; this.downloadUrl = downloadUrl; } @Override public void run() { // TODO Auto-generated method stub // super.run(); InputStream is = null; RandomAccessFile downFile = null; HttpURLConnection con = null; try { URL url = new URL(downloadUrl); con = (HttpURLConnection) url.openConnection(); con.setReadTimeout(readTimeOut);// 设置主机读取超时时间 con.setConnectTimeout(connectTimeOut);// 设置连接超时时间 // 断点下载所需 Range:bytes=x-y; con.setRequestProperty("Range", "bytes=" + String.valueOf(downloadLength) + "-"); is = con.getInputStream(); int fileLength = con.getContentLength();// 获取文件长度 Log.v("fileLength", String.valueOf(fileLength)); exeDownLoadInit(downloadLength, fileLength);// 下载初始化回调,返回已下载大小和文件总大小 File file = new File(path); if (!file.exists()) { file.mkdir(); } String[] str = downloadUrl.split("/"); String fileName = str[str.length - 1]; File file1 = new File(path + fileName); if (!file1.exists()) { file1.createNewFile(); } else { } downFile = new RandomAccessFile(file1, "rw"); downFile.seek(downloadLength);// 定位文件已经写入的位置,断点下载使用 byte[] data = new byte[1024]; int len; while ((len = is.read(data)) != -1) { // 文件写出,使用write(data,0,len)这个方法,当读取的长度小于1024,则只写入读取的长度 // 如果使用write(data)方法,则当长度不够1024,就会在后面自动补0 downFile.write(data, 0, len); downloadLength += len; downLoadUtil.downloadLength += len; progressNotifyCount++; // if(progressNotifyCount%100==0){ // 这个运算就相当于progressNotifyCount%100==0 // 计算机进行二进制运算速度更快,可做android优化使用 // 每下载100字节,就回调一次进度,供更新进度条使用 if ((progressNotifyCount & (100 - 1)) == 0) { exeDownLoadProgress(downloadLength); } // 暂停函数 if (!isDownloading) { return; } } //下载完成回调 if (downloadLength == fileLength) { exeDownloadComplete(fileLength); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { downFile.close(); is.close(); con.disconnect(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } // 交由主线程处理监听结果 private void exeDownLoadProgress(final int downloadLength) { handler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub listener.downloadProgress(downloadLength); } }); } private void exeDownLoadInit(final int downloadLength, final int fileLength) { handler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub listener.downloadInit(downloadLength, fileLength); } }); } private void exeDownloadComplete(final int fileLength) { handler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub listener.complete(fileLength); } }); } /** * 下载监听器 * * @author Administrator * */ public static interface OnDownLoadListener { /** * 请求完成回调 * * @param fileLength */ void complete(int fileLength); /** * 进度更新 * * @param downloadLength */ void downloadProgress(int downloadLength); /** * 下载初始化 * * @param fileLength */ void downloadInit(int downloadLength, int fileLength); } public void setListener(OnDownLoadListener listener) { this.listener = listener; } public void stop() { this.isDownloading = false; // downloadThread.getId(); } public void restart() { isDownloading = true; downLoad(requestUrl, path, downloadLength); } }
Demo资源下载
相关文章推荐
- 网络中的身份保护与信息保护
- CentOS 7.0 图解网络安装全过程
- Java利用Http模拟表单提交
- 网络协议HTTP、TCP/IP、Socket
- 事件函数块的返回值https://msdn.microsoft.com论述
- 使用Volley加载网络图片
- Linux网络编程--自定义套接字描述符判定函数issockettype
- 收益最大
- 一次完整的HTTP请求所经历的7个步骤
- Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
- Android获取当前网络状态
- Android获取当前网络状态
- 开启android板子的adb网络连接
- TIdHTTPResponseInfo 中文乱码问题解决
- httpClenit的post出现乱码问题
- P2P,UDP和TCP穿透NAT
- 在Ubuntu下运行tinyhttpd及其测试例子
- 2015.7.9(POST、GET请求限制)
- CenOS安装httpie
- 深度学习概述:从感知机到深度网络