利用多线程分段下载远程文件(callable+ExecutorService)
package com.etc.test;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
* 利用多线程分段下载远程文件
* @author Administrator
*
*/
public class CallableDownload{
//指定文件下载的路径
private static final String urlpath="http://download.ydstatic.com/notewebsite/downloads/YNote.exe";//会有点大,稍等一下就下完了
//指定下载线程的个数(分成四段)
private static final int Thread_COUNT=4;
private int fileSize;//请求的文件大小
private String realFileName;//请求资源的文件名
//创建一个文件,将远程文件写入该文件中
private File filename= new File("E:\\YNote.exe");
//创建Logger对象,以便进行日志记录
private static Logger logger=Logger.getLogger("CallableDownload");
public static void main(String[] args) {
try {
new CallableDownload().dowload();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void dowload() throws Exception{
URL url=new URL(urlpath);
logger.info(String.format("连接服务器:%s://%s", url.getProtocol(),url.getHost()));
HttpURLConnection conn=(HttpURLConnection)url.openConnection();//打开连接
conn.setRequestMethod("GET");//用get请求
conn.setConnectTimeout(5000);//设置连接的超时时间为5秒
int code=conn.getResponseCode();//得到服务器的响应码
if(code==200){//如果响应码为200,说明请求资源成功
this.fileSize =conn.getContentLength();//请求资源的大小
//conn.getContentLengthLong();
String[] temp = url.getFile().split("/");
if (temp.length != 0) {
this.realFileName = temp[temp.length - 1];//获取文件名
}
logger.info(String.format("文件名:%s 大小:%s", this.realFileName, this.fileSize));
//新建一个随机访问的文件
RandomAccessFile raf=new RandomAccessFile(filename, "rw");//第一个文件参数,第二个为模式
//设置随机文件大小为服务器端文件的大小
raf.setLength(fileSize);
//raf.close();
//计算每个线程下载的块的大小
int blockSize = conn.getContentLength() / Thread_COUNT;
List<CallableDownTask> tasks = new ArrayList<>();
for (int threadId = 1; threadId <= Thread_COUNT; threadId++) {
CallableDownTask task;
int startIndex = (threadId - 1) * blockSize;
int endIndex = threadId * blockSize - 1;
if (threadId == Thread_COUNT) {
endIndex = fileSize;
}
logger.info("线程:" + threadId + " 正在下载部分文件 :" + startIndex + "===>" + endIndex);
task=new CallableDownTask (startIndex, endIndex);
tasks.add(task);
}
logger.info(String.format("正在下载,请稍等……%s",realFileName));
ExecutorService service = Executors.newFixedThreadPool(Thread_COUNT);
service.invokeAll(tasks);
service.shutdownNow();//下载完成后,关闭资源
filename.renameTo(new File(realFileName));
logger.info(String.format("完成下载:%s",realFileName));
}
}
/**
* 下载文件的线程用
*/
class CallableDownTask implements Callable<String>{
//线程下载的起始点
private int startdown;
//线程下载的结束点
private int enddown;
public CallableDownTask(int startdown,int enddown){
this.startdown=startdown;
this.enddown=enddown;
}
public String call() throws Exception {
URL url=new URL(urlpath);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);//设置连接的超时时间为5秒
//设置头部的参数,表示此线程是请求服务器资源的某一部分
conn.setRequestProperty("Range","bytes="+startdown+"-"+enddown);
InputStream is=conn.getInputStream();
byte[] buf=new byte[1024];
//新创建一个RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile(filename, "rw");
//将写文件的指针指向下载的起始点
raf.seek(startdown);
int filelength=0;
/* while ((filelength = is.read(buf)) != -1) {
raf.write(buf);// 错误的,会导致下载的文件不完整,因为用这个方法,可能带来一个问题,最后一次可能实际写入会比原来的大(最后一次不满1024个字节的时候)
}*/
while ((filelength = is.read(buf))!=-1) {//如果没有可用的字节,因为流是在文件的末尾,会返回-1
raf.write(buf,0,filelength);// 所以还是带上实际的字节数
}
raf.close();
is.close();
return Thread.currentThread().getName();
}
}
}
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
* 利用多线程分段下载远程文件
* @author Administrator
*
*/
public class CallableDownload{
//指定文件下载的路径
private static final String urlpath="http://download.ydstatic.com/notewebsite/downloads/YNote.exe";//会有点大,稍等一下就下完了
//指定下载线程的个数(分成四段)
private static final int Thread_COUNT=4;
private int fileSize;//请求的文件大小
private String realFileName;//请求资源的文件名
//创建一个文件,将远程文件写入该文件中
private File filename= new File("E:\\YNote.exe");
//创建Logger对象,以便进行日志记录
private static Logger logger=Logger.getLogger("CallableDownload");
public static void main(String[] args) {
try {
new CallableDownload().dowload();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void dowload() throws Exception{
URL url=new URL(urlpath);
logger.info(String.format("连接服务器:%s://%s", url.getProtocol(),url.getHost()));
HttpURLConnection conn=(HttpURLConnection)url.openConnection();//打开连接
conn.setRequestMethod("GET");//用get请求
conn.setConnectTimeout(5000);//设置连接的超时时间为5秒
int code=conn.getResponseCode();//得到服务器的响应码
if(code==200){//如果响应码为200,说明请求资源成功
this.fileSize =conn.getContentLength();//请求资源的大小
//conn.getContentLengthLong();
String[] temp = url.getFile().split("/");
if (temp.length != 0) {
this.realFileName = temp[temp.length - 1];//获取文件名
}
logger.info(String.format("文件名:%s 大小:%s", this.realFileName, this.fileSize));
//新建一个随机访问的文件
RandomAccessFile raf=new RandomAccessFile(filename, "rw");//第一个文件参数,第二个为模式
//设置随机文件大小为服务器端文件的大小
raf.setLength(fileSize);
//raf.close();
//计算每个线程下载的块的大小
int blockSize = conn.getContentLength() / Thread_COUNT;
List<CallableDownTask> tasks = new ArrayList<>();
for (int threadId = 1; threadId <= Thread_COUNT; threadId++) {
CallableDownTask task;
int startIndex = (threadId - 1) * blockSize;
int endIndex = threadId * blockSize - 1;
if (threadId == Thread_COUNT) {
endIndex = fileSize;
}
logger.info("线程:" + threadId + " 正在下载部分文件 :" + startIndex + "===>" + endIndex);
task=new CallableDownTask (startIndex, endIndex);
tasks.add(task);
}
logger.info(String.format("正在下载,请稍等……%s",realFileName));
ExecutorService service = Executors.newFixedThreadPool(Thread_COUNT);
service.invokeAll(tasks);
service.shutdownNow();//下载完成后,关闭资源
filename.renameTo(new File(realFileName));
logger.info(String.format("完成下载:%s",realFileName));
}
}
/**
* 下载文件的线程用
*/
class CallableDownTask implements Callable<String>{
//线程下载的起始点
private int startdown;
//线程下载的结束点
private int enddown;
public CallableDownTask(int startdown,int enddown){
this.startdown=startdown;
this.enddown=enddown;
}
public String call() throws Exception {
URL url=new URL(urlpath);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);//设置连接的超时时间为5秒
//设置头部的参数,表示此线程是请求服务器资源的某一部分
conn.setRequestProperty("Range","bytes="+startdown+"-"+enddown);
InputStream is=conn.getInputStream();
byte[] buf=new byte[1024];
//新创建一个RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile(filename, "rw");
//将写文件的指针指向下载的起始点
raf.seek(startdown);
int filelength=0;
/* while ((filelength = is.read(buf)) != -1) {
raf.write(buf);// 错误的,会导致下载的文件不完整,因为用这个方法,可能带来一个问题,最后一次可能实际写入会比原来的大(最后一次不满1024个字节的时候)
}*/
while ((filelength = is.read(buf))!=-1) {//如果没有可用的字节,因为流是在文件的末尾,会返回-1
raf.write(buf,0,filelength);// 所以还是带上实际的字节数
}
raf.close();
is.close();
return Thread.currentThread().getName();
}
}
}