java 实现文件的断点续传(文件的分段上载)
java 实现文件的断点续传(文件的分段下载)
断点续传的原理:
把一个文件分为n个小文件,程序分n个线程去下载每一个小文件。阅读有关资料,IE浏览器传递给服务端的时候可以传递一个请求信息"Range":如:RANGE: bytes=2000070- 一看就知道告诉服务器下载的时候从2000070字节开始下载。值得注意的是response.getResponseCode()为206,不再是200了。
上代码:
/** * 下载工具类 * * @author aokunsang * */ public class FileDownloader { private HttpURLConnection conn; public static void main(String[] args) throws Exception { FileDownloader load = new FileDownloader(); load.download(); } /** * 开始下载 */ public void download() throws Exception { HttpConnect connect = new HttpConnect(1); int fileSize = 0, threadSize = 3; // 文件长度和线程数 conn = connect.initConnction(); conn.connect(); if (conn.getResponseCode() == 200) { fileSize = conn.getContentLength(); conn.disconnect(); } int perthThreadSize = fileSize / 3 + 1; //每个线程需要下载的文件大小 RandomAccessFile raf = new RandomAccessFile(new File("D://ca.mp3"), "rw"); raf.setLength(fileSize); raf.close(); long startTime = System.currentTimeMillis(); for (int i = 0; i < threadSize; i++) { int startpos = i * perthThreadSize; //线程开始下载的位置 RandomAccessFile raff = new RandomAccessFile(new File("D://ca.mp3"), "rw"); raff.seek(startpos); new myThread(startpos, perthThreadSize, i, raff).start(); } long endTime = System.currentTimeMillis(); while(Thread.activeCount()>1){} //防止main线程结束而导致下载线程被销毁 System.out.println("--------------下载完成,共耗时:"+(endTime-startTime)/(60*1000)+"分钟--------"); } class myThread extends Thread { private int startpos; private int perThreadSize; private int threadId; private RandomAccessFile raf; public myThread(int startpos, int perThreadSize, int threadId, RandomAccessFile raf) { this.startpos = startpos; this.perThreadSize = perThreadSize; this.threadId = threadId; this.raf = raf; } @Override public void run() { HttpConnect connect = new HttpConnect(0); HttpURLConnection con = connect.initConnction(); con.setRequestProperty("Range", "bytes=" + this.startpos + "-"); try { InputStream is = con.getInputStream(); byte[] bt = new byte[1024]; int length = 0; int len = 0; while (length < this.perThreadSize && (len = is.read(bt)) != -1) { raf.write(bt, 0, len); length += len; } raf.close(); is.close(); System.out.println("线程"+threadId+"完成!"); } catch (Exception e) { e.printStackTrace(); } } } class HttpConnect { private int flag; public HttpConnect(int flag) { this.flag = flag; } public HttpURLConnection initConnction() { HttpURLConnection connection = null; try { URL url = new URL(HttpConnectParams.URLSTRING.content); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(Integer .parseInt(HttpConnectParams.CONNECTTIEMEDOUT.content)); connection.setRequestMethod(HttpConnectParams.POST.content); connection.setRequestProperty(HttpConnectParams.ACCECT.header, HttpConnectParams.ACCECT.content); connection.setRequestProperty( HttpConnectParams.ACCECT_LANGAGE.header, HttpConnectParams.ACCECT_LANGAGE.content); connection.setRequestProperty(HttpConnectParams.CHARSET.header, HttpConnectParams.CHARSET.content); if (flag == 1) { connection.setRequestProperty( HttpConnectParams.KEEPCONNECT.header, HttpConnectParams.KEEPCONNECT.content); } } catch (Exception e) { connection = null; } return connection; } } }
一/**
* HTTP请求的一些常量信息 * @author aokunsang * */ public enum HttpConnectParams { /** * URL地址(mp3格式的音乐文件) */ URLSTRING("http://www.61mp3.cn/music/%B6%F9%CD%AF%B8%E8%C7%FA/%CA%AE%B6%FE%C9%FA%D0%A4%B8%E8.mp3"), /** * 请求的方式 */ POST("GET"), /** * 请求的格式 */ ACCECT("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"), /** * 请求的语言 */ ACCECT_LANGAGE("Accept-Language","zh-CN"), /** * 请求的字符集编码 */ CHARSET("Charset","UTF-8"), /** * 链接的超时数 */ CONNECTTIEMEDOUT("5000"), /** * 保持链接 */ KEEPCONNECT("Connection","Keep-Alive"); public String header; //标题 public String content; //内容 private HttpConnectParams(String header,String content) { this.header = header; this.content = content; } private HttpConnectParams(String content){ this.content = content; } }