断点续传JAVA实现


支持H5 Video标签播放,迅雷下载


/**
 * 断点续传工具
 * @author lxycx_xc
 * 时间:2017年11月30日
 */
public class BreakpointResume {
	
	private static Logger log = Logger.getLogger(BreakpointResume.class);
	
	
	/**下载操作,支持断点续传*/
	public static void download(HttpServletRequest req,HttpServletResponse resp,String filepath) throws NumberFormatException, IOException{
		//请求头参数
		File file = new File(filepath);
		Long fileSize = file.length();
		Long lasttime = file.lastModified();
		Long size = fileSize;
		int i = 0;
		
		String range = req.getHeader("Range");
		String ifm = req.getHeader("If-Modified-Since");
		if(ifm!=null&&Long.parseLong(ifm)<lasttime){//检查文件修改时间判断是否启用缓存
			resp.setStatus(304);
		}else{
			byte[] buff = new byte[524288];//1024*1024/2
			RandomAccessFile raf  = new RandomAccessFile(file, "rw");
			BufferedOutputStream bfo = new BufferedOutputStream(resp.getOutputStream());

			try {
				if(range!=null){//断点续传请求			
					size = (long)(5242880);//限制每次视频输出的大小 
					String[] ranges = range.replace("bytes=", "").split("-");
					
					if(ranges.length<2){//为Content-Range参数做铺垫
						ranges = new String[]{ranges[0],"0"};
						if(fileSize-Long.parseLong(ranges[0])>size){
							ranges[1] = String.valueOf(Long.parseLong(ranges[0])+size);	
						}else{
							ranges[1] = String.valueOf(fileSize-1);						
						}
					}
					
					raf.seek(Long.parseLong(ranges[0]));//从指定位置开始读取
					resp.setHeader("Last-Modified", String.valueOf(lasttime));//文件最后修改时间
					resp.setHeader("Content-Range", "bytes "+StringUtils.join(ranges, "-")+"/"+fileSize);//请求的数据 开始-结束/文件总大小
					resp.setStatus(206);
				}
				int len = 0;
				while((len=raf.read(buff))>0&&i<size){

					bfo.write(buff);
					bfo.flush();
					i+=len;
					
					log.debug("本次输出:"+buff.length);
				}
			} catch (Exception e) {
				log.info("输出流非正常关闭:");
			} finally{
				raf.close();
				bfo.close();
				log.info("当前请求共输出:"+i);
			}

		}
	}

}

原文地址:https://www.cnblogs.com/qixidi/p/10219606.html