• 【转】【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

  • 相关阅读:
    toodifficult 题解
    Code Chef February Challenge 2019题解
    LOJ#3085. 「GXOI / GZOI2019」特技飞行(KDtree+坐标系变换)
    LOJ#3084. 「GXOI / GZOI2019」宝牌一大堆(递推)
    LOJ#3083. 「GXOI / GZOI2019」与或和(单调栈)
    LOJ#6046. 「雅礼集训 2017 Day8」爷(分块)
    LOJ#6045. 「雅礼集训 2017 Day8」价(最小割)
    LOJ#6044. 「雅礼集训 2017 Day8」共(Prufer序列)
    BZOJ4766: 文艺计算姬(Prufer序列)
    BZOJ3729: Gty的游戏(伪ETT)
  • 原文地址:https://www.cnblogs.com/lensener/p/7880257.html
Copyright © 2020-2023  润新知