Java多线程断点续传下载

介绍了一个用于实现多线程断点续传下载功能的实用工具类,该工具类能够将大文件分割成多个部分,并利用多个线程同时下载这些部分,从而提高下载速度。同时支持断点续传功能,即使下载过程中断也能从上次停止的地方继续下载。
摘要由CSDN通过智能技术生成

提示:多线程环境下不能使用JUNIT进行测试,除非你能很好的控制,因为这个问题,浪费了很长时间。


/**
 * 多线程断点下载工具类
 * @author Shmily
 */
public class FileDownloadUtils {
	private static Logger logger = Logger.getLogger(FileDownloadUtils.class);  
	/**
	 * 多线程文件下载
	 * @param path 文件下载路径 eg:/mnt/*.txt
	 * @param storePath 文件的存储路径  eg:/mnt/sdcard/
	 * @param threadNumber 开启的线程数
	 * @return 是否下载成功
	 */
	public static boolean FileDownload(String path,String storePath,Integer threadNumber){
		//如果threadNumber为NULL,则默认为三个线程下载文件
		int localThreadNumber=(threadNumber==null)?3:threadNumber.intValue();
		URL downloadUrl=null;
		int fileSize=0;//下载的文件的大小
		int fileBlock=0;//每个线程下载的文件块大小
		try {
			downloadUrl=new URL(path);
			//打开链接
			HttpURLConnection coon= (HttpURLConnection)downloadUrl.openConnection();
			coon.setRequestMethod("GET");
			//请求最长延时时间60s
			coon.setReadTimeout(60*1000);
			int status=coon.getResponseCode();
			if(status==200){
				logger.info("网络响应成功");
				//获得网络响应的文件的大小
				fileSize=coon.getContentLength();
				//计算每个线程下载的文件块的大小
				fileBlock=fileSize/localThreadNumber;
			}else{
				logger.error("网络响应失败");
			}
		} catch (Exception e1) {
			logger.error("网络地址不存在");
		}
		RandomAccessFile tempFile=null;//在本地存储的文件
		try {
			File storeFile=new File(storePath+path.substring(path.lastIndexOf("/")+1));
			tempFile=new RandomAccessFile(storeFile, "rwd");
			tempFile.setLength(fileSize);//设置文件大小
			tempFile.close();
			//计算每个线程的起始下载位置
			for(int i=0;i<threadNumber;i++){
				int start=i*fileBlock;
				int end=0;
				if(i==(threadNumber-1)){
					end=fileSize;
				}else{
					end=(i+1)*fileBlock-1;
				}
				//创建新线程
				DownloadThread tempThread=new DownloadThread(i, start, end, path,storeFile);
				tempThread.start();
				logger.info("线程"+i+"开始下载文件,开始位置:"+start+"结束位置:"+end);
			}
		} catch (Exception e) {
			logger.error("创建本地存储文件失败");
		}
		return true;
	}
}
	/**
	 * 下载线程类
	 * @author Shmily
	 */
	class DownloadThread extends Thread{
		private static Logger logger = Logger.getLogger(DownloadThread.class);  
		private int threadId;//线程ID
		private int start;//线程下载文件的数据起始位置
		private int end;//线程下载文件的数据结束位置
		private String path;//欲下载的文件的存储路径
		private File storeFile;//文件的存储路径
		public DownloadThread(int threadId, int start, int end,String path, File storeFile) {
			this.threadId = threadId;
			this.start = start;
			this.end = end;
			this.path = path;
			this.storeFile=storeFile;
		}
	
		@Override
		public void run() {
	    	Properties pro=StreamUtils.loadProperty("/com/zgs/stream/util/config.properties");
			//该线程下载的文件未下载完毕
			if(pro!=null&&pro.getProperty(threadId+"")!=null){
				logger.info("线程"+threadId+"从"+(String)pro.getProperty(threadId+"")+"继续下载");
			   String val=(String)pro.getProperty(threadId+"");
			   if(Integer.parseInt(val)>start)
				   //更新下载起始位置
				   start=Integer.parseInt(val);
			}
			try {
				URL downloadUrl = new URL(path);
				//打开链接
				HttpURLConnection coon= (HttpURLConnection)downloadUrl.openConnection();
				coon.setRequestMethod("GET");
				//请求最长延时时间5s
				coon.setReadTimeout(5000);
				coon.setRequestProperty("Range", "bytes="+start+"-"+ end);
				int status=coon.getResponseCode();
				logger.info("状态码:"+status);
				//多线程断点下载时服务器的响应的状态吗为206
				if(status==206||status==200){
				   //获得存储在本地的文件
				   RandomAccessFile tempFile=new RandomAccessFile(storeFile, "rwd");
				   //定位写文件的起始位置
				   tempFile.seek(start);
				   //打开服务器响应
				   InputStream in=coon.getInputStream();
				   //缓冲区
				   byte[] buffer=new byte[1024];
				   int len=0;
				   int currentLocation=start;//当前读取的文件位置
				   //读写数据
				   while((len=in.read(buffer))!=-1){
					   logger.info("线程"+threadId+"正在读取"+currentLocation);
					   tempFile.write(buffer,0,len);
					   currentLocation+=len;
					   //记录文件下一次开始下载的位置
					   StreamUtils.updateProperty("/com/zgs/stream/util/config.properties", threadId+"",currentLocation+"");
				   }
				   //移除对应的key
				   StreamUtils.updateProperty("/com/zgs/stream/util/config.properties", threadId+"");
				   tempFile.close();
				   logger.info("线程"+threadId+"下载完毕");
				}
			} catch (Exception e) {
				logger.error("网络连接异常");
			}
			
		}
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值