【转】【JAVA应用】多线程断点下载

【转自】

光仔December

http://blog.csdn.net/acmman

问题:多线程下载的好处?

多线程下载比单线程下载快,主要的原因是采用多线程下载,可以抢占更多的服务器资源。抢占Cpu的处理空间,实现更快的下载速度

问题:多线程下载位置的确定?

开启N条线程下载文件,假设文件大小为buf,那么每条线程的下载量为:
buf%N==0?buf/N:buf/N+1;

那么,每一条线程应该从网络文件的什么位置开始下载??

假设线程id号threadid为0,1,2,每一条线程下载的数据量为block=4

第一个文件从threadid*block开始下载,结束位置(threadid+1)*block-1

所以公式为:
int start=threadid*block;
int end=(threadid+1)*block-1;

多线程下载源码(仅供参考)

  1. package cn.deu.hpu.download;  
  2.   
  3. import java.io.File;  
  4. import java.io.InputStream;  
  5. import java.io.RandomAccessFile;  
  6. import java.net.HttpURLConnection;  
  7. import java.net.URL;  
  8.   
  9. public class MulThreadDownLoad {  
  10.       
  11.     public static void main(String[] args) throws Exception{  
  12.         String path="http://192.168.111.104:8080/web/gg.jpg";  
  13.         new MulThreadDownLoad().download(path,3);  
  14.     }  
  15.       
  16.     /*下载文件 
  17.      * path 网络文件路径 
  18.      * */  
  19.     public void download(String path,int threadsize)throws Exception{  
  20.         URL url=new URL(path);  
  21.         HttpURLConnection conn=(HttpURLConnection) url.openConnection();  
  22.         conn.setConnectTimeout(5000);  
  23.         conn.setRequestMethod("GET");  
  24.         if(conn.getResponseCode()==200){  
  25.             //取得网络文件的长度  
  26.             int length=conn.getContentLength();  
  27.             File file=new File(getFilename(path));  
  28.             //随机访问文件类(生成一个与网络文件长度相等的本地文件)  
  29.             RandomAccessFile accessFile=new RandomAccessFile(file, "rwd");  
  30.             accessFile.setLength(length);  
  31.             accessFile.close();  
  32.               
  33.             //计算每条线程需要下载的数据量  
  34.             int block=length%threadsize==0?length/threadsize:length/threadsize+1;  
  35.             for (int threadid = 0; threadid< threadsize; threadid++) {  
  36.                 new DownloadThread(threadid,block,url,file).start();  
  37.             }  
  38.         }else{  
  39.             System.out.println("下载失败!");  
  40.         }  
  41.           
  42.     }  
  43.   
  44.     private String getFilename(String path) {  
  45.         //从URL地址的最后一个"/"后开始记录文件名  
  46.         return path.substring(path.lastIndexOf("/")+1);  
  47.     }  
  48.       
  49.     private class DownloadThread extends Thread{  
  50.         private int threadid;  
  51.         private int block;  
  52.         private URL url;  
  53.         private File file;  
  54.         public DownloadThread(int threadid,int block,URL url,File file){  
  55.             this.threadid=threadid;  
  56.             this.block=block;  
  57.             this.url=url;  
  58.             this.file=file;  
  59.         }  
  60.           
  61.         public void run(){  
  62.             //计算该线程从网络文件的什么位置开始下载  
  63.             int start=threadid*block;  
  64.             //下载到网络文件的什么位置结束  
  65.             int end=(threadid+1)*block-1;  
  66.             try {  
  67.                 RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");  
  68.                 //从某一个位置开始写入数据  
  69.                 accessFile.seek(start);               
  70.                 HttpURLConnection conn=(HttpURLConnection) url.openConnection();  
  71.                 conn.setConnectTimeout(5000);  
  72.                 conn.setRequestMethod("GET");  
  73.                 //指定行网络文件的某个区域下载数据(开始位置-结束位置)  
  74.                 conn.setRequestProperty("Range", "bytes="+start+"-"+end);  
  75.                 //请求某一段数据的话,请求码不是200,是206  
  76.                 if(conn.getResponseCode()==206){  
  77.                     InputStream instream=conn.getInputStream();  
  78.                     byte [] buffer=new byte[1024];  
  79.                     int len=0;  
  80.                     while((len=instream.read(buffer))!=-1){  
  81.                         accessFile.write(buffer,0,len);  
  82.                     }  
  83.                     accessFile.close();  
  84.                     instream.close();  
  85.                 }  
  86.                 System.out.println("第"+(threadid+1)+"线程已经下载完成");  
  87.             } catch (Exception e) {  
  88.                 e.printStackTrace();  
  89.             }  
  90.         }  
  91.     }  
  92. }  
package cn.deu.hpu.download;

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

public class MulThreadDownLoad {
	
	public static void main(String[] args) throws Exception{
		String path="http://192.168.111.104:8080/web/gg.jpg";
		new MulThreadDownLoad().download(path,3);
	}
	
	/*下载文件
	 * path 网络文件路径
	 * */
	public void download(String path,int threadsize)throws Exception{
		URL url=new URL(path);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
		if(conn.getResponseCode()==200){
			//取得网络文件的长度
			int length=conn.getContentLength();
			File file=new File(getFilename(path));
			//随机访问文件类(生成一个与网络文件长度相等的本地文件)
			RandomAccessFile accessFile=new RandomAccessFile(file, "rwd");
			accessFile.setLength(length);
			accessFile.close();
			
			//计算每条线程需要下载的数据量
			int block=length%threadsize==0?length/threadsize:length/threadsize+1;
			for (int threadid = 0; threadid< threadsize; threadid++) {
				new DownloadThread(threadid,block,url,file).start();
			}
		}else{
			System.out.println("下载失败!");
		}
		
	}

	private String getFilename(String path) {
		//从URL地址的最后一个"/"后开始记录文件名
		return path.substring(path.lastIndexOf("/")+1);
	}
	
	private class DownloadThread extends Thread{
		private int threadid;
		private int block;
		private URL url;
		private File file;
		public DownloadThread(int threadid,int block,URL url,File file){
			this.threadid=threadid;
			this.block=block;
			this.url=url;
			this.file=file;
		}
		
		public void run(){
			//计算该线程从网络文件的什么位置开始下载
			int start=threadid*block;
			//下载到网络文件的什么位置结束
			int end=(threadid+1)*block-1;
			try {
				RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
				//从某一个位置开始写入数据
				accessFile.seek(start);				
				HttpURLConnection conn=(HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setRequestMethod("GET");
				//指定行网络文件的某个区域下载数据(开始位置-结束位置)
				conn.setRequestProperty("Range", "bytes="+start+"-"+end);
				//请求某一段数据的话,请求码不是200,是206
				if(conn.getResponseCode()==206){
					InputStream instream=conn.getInputStream();
					byte [] buffer=new byte[1024];
					int len=0;
					while((len=instream.read(buffer))!=-1){
						accessFile.write(buffer,0,len);
					}
					accessFile.close();
					instream.close();
				}
				System.out.println("第"+(threadid+1)+"线程已经下载完成");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

转载请注明出处!程序猿之洞:http://blog.csdn.net/acmman

原文地址:https://www.cnblogs.com/lensener/p/7880257.html