您的位置:首页 > 理论基础 > 计算机网络

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-

建立起连接之后,获取输入流:

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资源下载

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: