Java单线程文件下载,支持断点续传功能
前言:
程序下载文件时,有时会因为各种各样的原因下载中断,对于小文件来说影响不大,可以快速重新下载,但是下载大文件时,就会耗费很长时间,所以断点续传功能对于大文件很有必要。
文件下载的断点续传:
1、先下载临时文件,用于记录已下载大小:
2、http请求时设置Range参数
3、下载此次请求的数据;
直接上代码:
1 package com.test.service; 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 import java.text.NumberFormat; 9 10 import org.slf4j.Logger; 11 import org.slf4j.LoggerFactory; 12 import org.springframework.beans.factory.annotation.Value; 13 import org.springframework.stereotype.Component; 14 15 /** 16 * <p> 17 * 文件下载,可以支持断点续传 18 * 暂未使用 19 * </p> 20 * @author 21 * @version 1.0 22 * */ 23 @Component 24 public class DownloadOnly { 25 26 private static final Logger logger = LoggerFactory.getLogger(DownloadOnly.class); 27 28 @Value("${onair.download.ddxc:true}") 29 boolean ddxc = true; 30 31 int startIndex = 0; 32 33 long downloadSize = 0; 34 35 boolean downloadFinish = false; 36 37 int totleSize = 0; 38 39 public boolean download(String url,String file_path,int downloadTimeout){ 40 41 //起一个线程 检测下载进度 42 new Thread(new Runnable() { 43 44 @Override 45 public void run() { 46 try { 47 NumberFormat nt = NumberFormat.getPercentInstance(); 48 //设置百分数精确度3即保留三位小数 49 nt.setMinimumFractionDigits(1); 50 while(!downloadFinish){ 51 Thread.sleep(30000); 52 logger.debug("已下载大小{},进度{}",getDownloadSize(),nt.format(getDownloadSize()* 1.0 /totleSize)); 53 } 54 } catch (InterruptedException e) { 55 e.printStackTrace(); 56 } 57 58 } 59 }).start(); 60 61 logger.info("下载文件:源路径{},目标路径:{}",url,file_path); 62 RandomAccessFile raf = null; 63 InputStream in = null; 64 65 try { 66 URL file_url = new URL(url); 67 HttpURLConnection conn = (HttpURLConnection)file_url.openConnection(); 68 conn.setConnectTimeout(downloadTimeout); 69 conn.setRequestMethod("GET"); 70 File tmpFile = new File(file_path+"_tmp"); 71 if(ddxc){ 72 if(tmpFile.exists() && tmpFile.isFile()){ 73 downloadSize = tmpFile.length(); 74 startIndex = (int)downloadSize; 75 } 76 conn.setRequestProperty("Range", "bytes=" + startIndex + "-"); 77 }else{ 78 if(tmpFile.exists() && tmpFile.isFile()) 79 tmpFile.delete(); 80 } 81 int status = conn.getResponseCode(); 82 totleSize = (int)downloadSize + conn.getContentLength(); 83 logger.info("文件总大小{},下载请求获得的返回状态码:{},需要下载的大小{}",totleSize,status,totleSize-downloadSize); 84 if(status== 200 || status == 206 ){ 85 raf = new RandomAccessFile(tmpFile, "rwd"); 86 raf.seek(startIndex); 87 in = conn.getInputStream(); 88 byte[] buffer = new byte[1024]; 89 int size = 0; 90 while((size=in.read(buffer)) !=-1 ){ 91 raf.write(buffer, 0, size); 92 downloadSize += size; 93 } 94 raf.close(); 95 in.close(); 96 File dest = new File(file_path); 97 return tmpFile.renameTo(dest); 98 } 99 } catch (Throwable e) { 100 logger.error("文件下载失败:{}",e.getMessage(),e); 101 }finally { 102 downloadFinish = true; //下载完成或中断 103 } 104 return false; 105 } 106 107 public long getDownloadSize() { 108 return downloadSize; 109 } 110 111 public static void main(String[] args) { 112 DownloadOnly downloadOnly = new DownloadOnly(); 113 } 114 115 }