断点续传的原理:
把一个文件分为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;
}
}