多线程断点下载

大致流程如下图


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

/**
 * 多线程下载器
 */
public class MultiDownloader {
	/**
	 * 开启几个线程从服务器下载数据
	 */
	public static int threadCount = 3;
	
	public static int runningThreadCount ;
	// 服务器的文件,准备出来,tomcat服务器上.
	public static String path = "http://192.168.1.104:8080/setup.exe";

	// 多线程下载
	public static void main(String[] args) throws Exception {
		URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
		int code = conn.getResponseCode();
		if (code == 200) {
			int length = conn.getContentLength();
			System.out.println("服务器文件的长度为:" + length);
			RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rw");
			raf.setLength(length);
			raf.close();
			int blocksize = length / threadCount;
			runningThreadCount = threadCount;
			for (int threadId = 0; threadId < threadCount; threadId++) {
				int startIndex = threadId * blocksize;
				int endIndex = (threadId + 1) * blocksize - 1;
				if (threadId == (threadCount - 1)) {
					endIndex = length - 1;
				}
				new DownloadThread(threadId, startIndex, endIndex).start();
			}
		}
	}

	private static class DownloadThread extends Thread {
		/**
		 * 线程id
		 */
		private int threadId;
		/**
		 * 线程下载的理论开始位置
		 */
		private int startIndex;
		/**
		 * 线程下载的结束位置
		 */
		private int endIndex;
		/**
		 * 当前线程下载到文件的那一个位置了.
		 */
		private int currentPosition;

		public DownloadThread(int threadId, int startIndex, int endIndex) {
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			System.out.println(threadId + "号线程下载的范围为:" + startIndex
					+ "   ~~   " + endIndex);
			currentPosition = startIndex;
		}

		@Override
		public void run() {
			try {
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				//检查当前线程是否已经下载过一部分的数据了 
				File info = new File(threadId+".position");
				RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rw");
				if(info.exists()&&info.length()>0){
					FileInputStream fis = new FileInputStream(info);
					BufferedReader br = new BufferedReader(new InputStreamReader(fis));
					currentPosition = Integer.valueOf(br.readLine());
					conn.setRequestProperty("Range", "bytes="+currentPosition+"-"+endIndex);
					System.out.println("原来有下载进度,从上一次终止的位置继续下载"+"bytes="+currentPosition+"-"+endIndex);
					fis.close();
					raf.seek(currentPosition);//每个线程写文件的开始位置都是不一样的.
				}else{
				//告诉服务器 只想下载资源的一部分
					conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
					System.out.println("原来没有有下载进度,新的下载"+ "bytes="+startIndex+"-"+endIndex);
					raf.seek(startIndex);//每个线程写文件的开始位置都是不一样的.
				}
				InputStream is = conn.getInputStream();
				byte[] buffer = new byte[1024*1024*10];
				int len = -1;
				while((len = is.read(buffer))!=-1){
					//把每个线程下载的数据放在自己的空间里面.
//					System.out.println("线程:"+threadId+"正在下载:"+new String(buffer));
					raf.write(buffer,0, len);
					currentPosition+=len;
					File file = new File(threadId+".position");
					RandomAccessFile fos = new RandomAccessFile(file,"rwd");
					//System.out.println("线程:"+threadId+"写到了"+currentPosition);
					fos.write(String.valueOf(currentPosition).getBytes());
					fos.close();//fileoutstream数据是不一定被写入到底层设备里面的,有可能是存储在缓存里面.
					//raf 的 rwd模式,数据是立刻被存储到底层硬盘设备里面.
				}
				raf.close();
				is.close();
				System.out.println("线程:"+threadId+"下载完毕了...");
				File f = new File(threadId+".position");
				f.renameTo(new File(threadId+".position.finish"));
				synchronized (MultiDownloader.class) {
					runningThreadCount--;
					if(runningThreadCount<=0){
						for(int i=0;i
    
    



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值