多线程断点下载的实现

 

 

package mutidownloader;

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

/**
 * Java版多线程下载器 多线程下载的步骤: 1、本地创建一个大小跟服务器文件相同大小的临时文件
 * 2、计算分配几个线程去下载服务器上的资源,知道每个线程下载文件的位置 3、开启多个线程,每一个线程下载对应位置的文件
 * 4、如果所有线程都把自己的数据下载完毕了,服务器上的资源就被下载到本地
 * 
 * @author Administrator
 * 
 */
public class MutilDownloader {

	public static int ThreadCount = 3;//记录线程的个数
	public static int runningThread = ThreadCount;//记录运行的线程的个数
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		try {
			String path = "http://192.168.1.100:8080/download.exe";
			URL url = new URL(path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(5000);

			int code = conn.getResponseCode();
			if (code == 200) {
				// 服务器返回的数据的长度,实际上就是文件的大小
				int length = conn.getContentLength();
				System.out.println("文件总长度为:" + length);

				// 计算每一个线程下载的起始位置
				int blockSize = length / ThreadCount;
				for (int threadId = 1; threadId <= ThreadCount; threadId++) {
					int startIndex = (threadId - 1) * blockSize;
					int endIndex = threadId * blockSize - 1;
					if (threadId == ThreadCount) {
						endIndex = length;
					}
					System.out.println("线程" + threadId + "下载---" + startIndex
							+ "--->" + endIndex);
					
					// 开启多线程下载
					new DownloadThread(startIndex, endIndex, threadId, path)
							.start();
				}

			} else {
				System.out.println("下载失败");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 每一个子线程下载相应起始位置的数据
	 * 
	 * @author Administrator
	 * 
	 */
	public static class DownloadThread extends Thread {
		private int startIndex;
		private int endIndex;
		private int threadId;
		private String path;

		/**
		 * 
		 * @param startIndex
		 *            线程下载的开始位置
		 * @param endIndex
		 *            下载的结束位置
		 * @param threadId
		 *            线程ID
		 * @param path
		 *            下载文件在服务器上的位置
		 */
		public DownloadThread(int startIndex, int endIndex, int threadId,
				String path) {
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
			this.path = path;
		}

		@Override
		public void run() {

			try {
				
				//在线程开始前,先判断是否已经有了线程下载的记录,如果有了,则读取里面的开始地址,如果没有,则开始下载
				File tempFile = new File(threadId+".txt");
				if(tempFile.exists()&& tempFile.length()>0){
					FileInputStream fis = new FileInputStream(tempFile);
					byte[] temByte = new byte[1024];
					int len = fis.read(temByte);
					String downLength = new String(temByte,0,len);
					int downLengthInt = Integer.valueOf(downLength);
					startIndex = downLengthInt;//更改新的开始位置
					fis.close();
				}
				
				
				System.out.println("线程" + threadId + "新的下载位置---" + startIndex
						+ "--->" + endIndex);
				
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setRequestMethod("GET");
				// 重要:请求服务器下载文件指定位置的数据所要指定的参数。
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
						+ endIndex);
				conn.setConnectTimeout(5000);

				int code = conn.getResponseCode();// 如果请求服务器全部资源,成功返回200,如果指定了Range参数,成功返回206
				System.out.println("code=" + code);
				if (code == 206) {
					InputStream is = conn.getInputStream();
					// 因为涉及到开始和结束的位置,所以需要用到RandomAccessFile来随机定位文件的位置
					RandomAccessFile raf = new RandomAccessFile("setup.exe",
							"rwd");
					raf.seek(startIndex);// 定位文件
					int len = 0;

					// 完成断点的功能,就算中途程序出现异常,下次开始的时候,也能从上次结束的地方继续下载..原理是先把上次结束的位置保存起来
					int newStart = startIndex;// 下次开始时,新的开始位置
					
					byte[] buffer = new byte[1024];
					while ((len = is.read(buffer)) != -1) {
						raf.write(buffer, 0, len);
						
						
						newStart += len;// 记录当前下载的位置
						//保存当前下载的位置
						RandomAccessFile recodeFile = new RandomAccessFile(threadId+".txt","rwd");
						recodeFile.write((newStart+"").getBytes());
						recodeFile.close();
						System.out.println("线程:" + threadId + "新的下载位置"
								+ newStart);
					}
					is.close();
					raf.close();
					System.out.println("线程:" + threadId + "下载完毕了..");
				} else {
					System.out.println("下载失败");
				}

			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				//当前线程执行完毕,存活的线程个数就减1,当为0时,说明文件已经下载完成,就可以把记录文件删除
				runningThread--;
				if(runningThread==0){
					for(int i=1;i<=ThreadCount;i++){
						File delFile = new File(i+".txt");
						delFile.delete();
					}
				}
			}

		}
	}

}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值