Java 多线程断点下载原理

其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载,首先:你必须明白第一点,那么就是,什么是多线程下载,该知识点可以查看本博客上一篇文章,Android之多线程下载原理,断点下载呢,其实就是在这个的基础之上添加了一些东西,那么添加了什么东西了,现在来做一个详细的了解。


一、在下载的过程中,边下载,变用一个文件来记录下载的位置,也就是下载了多少的数据

       1.创建文件

       2.记录下载多少数据

       3.存储数据


二、第二次下载的时候,就去读取文件中是否存有数据,读取上次下载的位置,作为这次开始下载的位置

       1.创建文件对象

       2.检验是否有次文件和文件里面是否有数据

       3.读取数据,将数据拿给这次的开始位置,也就是从这个数据这里开始下载


三、文件下载完成之后,将记录的文件删除,一定要下载完成之后,在将文件删除,不然会跳出一些异常,比如,这次文件没了,就要重新开始下载等等


四、以上说了这些是不是稍微明白了些,那么下面来看看真正的实践吧


示例源码:

package com.zengtao.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @author zengtao
 */
public class DemoLoader {
	private static DemoLoader loader = new DemoLoader();
	private static int threadCount = 3;
	private static int runningThread = 3;

	private DemoLoader() {

	}

	public static DemoLoader getInstance() {
		return loader;
	}

	/**
	 * 去服务器端下载文件
	 * 
	 * @param path
	 *            服务器地址
	 */
	public void downFile(String path) {
		// 去服务器端获取文件的长度,在本地创建一个跟服务器一样大小的文件
		try {
			URL url = new URL(path);
			HttpURLConnection connection = (HttpURLConnection) url
					.openConnection();
			connection.setDoInput(true);
			connection.setRequestMethod("GET");
			connection.setReadTimeout(5000);
			int code = connection.getResponseCode();
			if (code == 200) {
				// 1.获取服务器端文件的长度
				int fileLength = connection.getContentLength();
				// 2.本地创建一个跟服务器一样大小的文件
				RandomAccessFile raf = new RandomAccessFile("setup.exe", "rwd");
				raf.setLength(fileLength);
				raf.close();
				// 3.假设三个线程下载
				int blockSize = fileLength / threadCount;
				for (int threadId = 0; threadId < threadCount; threadId++) {
					int startIndex = (threadId - 1) * blockSize;
					int endIndex = threadId * blockSize - 1;
					if (threadId == threadCount) {
						endIndex = fileLength;
					}

					// log 假设下载
					System.out.println("假设线程:" + threadId + ",下载:" + startIndex
							+ "--->" + endIndex);
					// 4.开始下载
					new DownLoadThread(threadId, startIndex, endIndex, path)
							.start();
				}
				System.out.println("文件总长度为:" + fileLength);
			} else {
				System.out.println("请求失败!");
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 下载文件的线程
	 * 
	 * @author Administrator zengtao
	 * 
	 */
	public class DownLoadThread extends Thread {
		private int threadId;
		private int startIndex;
		private int endIndex;
		private String path;

		/**
		 * 
		 * @param threadId
		 *            线程id
		 * @param startIndex
		 *            线程下载开始位置
		 * @param endIndex
		 *            线程下载结束位置
		 * @param path
		 *            线程下载结束文件放置地址
		 */
		public DownLoadThread(int threadId, int startIndex, int endIndex,
				String path) {
			super();
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.path = path;
		}

		@Override
		public void run() {
			super.run();
			try {
				// 1.检验是否有存的记录
				// ---------------------------------------------------
				File file = new File(threadId + ".txt");
				if (file.exists() && file.length() > 0) {
					FileInputStream fis = new FileInputStream(file);
					byte[] temp = new byte[1024];
					int leng = fis.read(temp);
					String loadLength = new String(temp, 0, leng);
					int load = Integer.parseInt(loadLength);
					startIndex = load;
					fis.close();
				}
				URL url = new URL(path);
				HttpURLConnection connection = (HttpURLConnection) url
						.openConnection();
				// 2.请求服务器下载部分的文件,制定开始的位置,和结束位置
				connection.setRequestProperty("Range", "bytes=" + startIndex
						+ "-" + endIndex);
				// log 真实下载
				System.out.println("真实线程:" + threadId + ",下载:" + startIndex
						+ "--->" + endIndex);
				connection.setDoInput(true);
				connection.setRequestMethod("GET");
				connection.setReadTimeout(5000);
				// 3.从服务器获取的全部数据,返回:200,从服务器获取部分数据,返回:206
				int code = connection.getResponseCode();
				System.out.println("code = " + code);
				InputStream is = connection.getInputStream();
				RandomAccessFile raf = new RandomAccessFile("setup.exe", "rwd");
				raf.seek(startIndex); // 随机写文件的时候,从什么时候开始
				int len = 0;
				int total = 0; // 记录下载多少
				byte[] buff = new byte[1024];
				while ((len = is.read(buff)) != -1) {
					RandomAccessFile info = new RandomAccessFile(threadId
							+ ".txt", "rwd");
					raf.write(buff, 0, len);
					total += len;
					info.write(("" + startIndex + total).getBytes()); // 4.存数据:(真正下载到开始的位置)下载的+开始的----------------------------------------
					info.close();
				}
				is.close();
				raf.close();
				System.out.println("线程:" + threadId + ",下载完成");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				// 5.notice一定要文件都下载完毕之后再将记录文件删除
				runningThread--;
				if (runningThread == 0) {
					for (int i = 1; i <= threadCount; i++) {
						File file = new File(i + ".txt");
						file.delete();
					}
					System.out.println("文件下载完毕,删除记录文件");
				}
			}
		}
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值