packagecom.test.service;importjava.io.File;importjava.io.InputStream;importjava.io.RandomAccessFile;importjava.net.HttpURLConnection;importjava.net.URL;importjava.util.concurrent.CountDownLatch;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Component;/***
* 多线程文件下载,提高大文件的下载速度(暂未使用)
*
**/@Componentpublic classMulitThreadDownload {private static Logger logger = LoggerFactory.getLogger(MulitThreadDownload.class);
@Value("${onair.download.threadsize:5}")private int threadSize = 5;
@Value("${onair.download.timeout:5000}")private intdownloadTimeout;static boolean flag = true;//消息
private final CountDownLatch msgDownLatch = new CountDownLatch(1);//工作线程
private final CountDownLatch workDownLatch = newCountDownLatch(threadSize);private DowloadRunnable[] dowloadRunnables = newDowloadRunnable[threadSize];public static voidmain(String[] args) {new MulitThreadDownload().downloadFile("", "G:\\123.mp4");
}public booleandownloadFile(String url,String filePath){
logger.debug("下载地址:{},目标文件路径:{}",url,filePath);try{
URL urlPath= newURL(url);
HttpURLConnection conn=(HttpURLConnection)urlPath.openConnection();
conn.setConnectTimeout(downloadTimeout);
conn.setRequestMethod("GET");int status =conn.getResponseCode();if(status == 200){ //200返回所有,206返回部分//文件长度
int length =conn.getContentLength();
logger.info("获取文件大小:{}",length);//创建下载文件 指定大小
RandomAccessFile raf = new RandomAccessFile(new File(filePath), "rwd");
raf.setLength(length);
raf.close();//释放资源//分块大小
int blockSize = length /threadSize;//创建工作线程
for (int i = 1; i <= threadSize; i++) {int startIndex = blockSize*(i-1);int endIndex = blockSize * i - 1;if(i ==threadSize){
endIndex=length;
}
logger.info("线程:{}下载文件开始点:{}结束点:{}",i,startIndex,endIndex);
dowloadRunnables[i-1] = newDowloadRunnable(url,filePath,msgDownLatch, workDownLatch, i,startIndex,endIndex);
Thread thread= new Thread(dowloadRunnables[i-1]);
thread.start();
thread.setUncaughtExceptionHandler(newThread.UncaughtExceptionHandler() {
@Overridepublic voiduncaughtException(Thread t, Throwable e) {
logger.debug("catch到异常",e);
flag= false;
}
});
}//通知工作线程启动,开始工作
msgDownLatch.countDown();
logger.debug("主线程阻塞,等待工作线程完成任务");//起一个线程监控下载进度//moniterLength(length);//阻塞主线程,等待工作线程完成
workDownLatch.await();
logger.debug("工作线程完成任务,主线程继续");returnflag;
}
}catch(Throwable e) {
logger.error("文件下载失败:"+e.getMessage(),e);
File file= newFile(filePath);if(file.exists()){
file.delete();//下载失败 删除临时文件
}
}return false;
}//输出下载进度
private void moniterLength(intlength) {new Thread(newRunnable() {
@Overridepublic voidrun() {while(getDownloadLength()
logger.debug("文件大小:{},目前下载大小:{},进度{}",length,getDownloadLength(),getDownloadLength()* 1.0 / (long)length);try{
Thread.sleep(10000);
}catch(InterruptedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}//监控下载进度
public intgetDownloadLength(){int length = 0;for (int i = 0; i < dowloadRunnables.length; i++) {
length+=dowloadRunnables[i].downloadLength;
}returnlength;
}
}//下载线程
class DowloadRunnable implementsRunnable{private static Logger logger = LoggerFactory.getLogger(DowloadRunnable.class);privateCountDownLatch msgDownLatch;privateCountDownLatch workDownLatch;private intthreadIndex;private intstartIndex;private intendIndex;privateString url;privateString filePath;public int downloadLength; //已下载大小
publicDowloadRunnable(String url, String filePath,
CountDownLatch msgDownLatch, CountDownLatch workDownLatch,int threadIndex, int startIndex, intendIndex) {this.url =url;this.filePath =filePath;this.msgDownLatch =msgDownLatch;this.workDownLatch =workDownLatch;this.threadIndex =threadIndex;this.startIndex =startIndex;this.endIndex =endIndex;
}
@Overridepublic voidrun() {try{//阻塞此线程,等待主线程给启动消息(msgDownLatch.countDown());
msgDownLatch.await();//具体工作
logger.info("线程{}任务开始",threadIndex);
URL urlPath= newURL(url);
HttpURLConnection conn=(HttpURLConnection)urlPath.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+endIndex);
conn.setRequestMethod("GET");int status =conn.getResponseCode();
logger.debug("线程{}请求返回的responseCode:{}",threadIndex,status);if(status==206){
InputStream in=conn.getInputStream();
RandomAccessFile raf= new RandomAccessFile(filePath, "rwd");
raf.seek(startIndex);byte[] buffer = new byte[2048];int length = 0;
logger.debug("线程{}开始写数据,开始点{}",threadIndex,startIndex);while((length = in.read(buffer)) != -1){//logger.debug("线程{}读取大小:{}",threadIndex,length);
raf.write(buffer, 0, length);//downloadLength += length;
}
raf.close();
in.close();
}else{
logger.error("文件下载失败,状态码:"+status);throw new Exception("文件下载失败,状态码:"+status);
}
logger.info("线程{}任务完成",threadIndex);//工作完成
workDownLatch.countDown();
}catch(Throwable e) {
logger.error(e.getMessage(),e);
e.printStackTrace();
}
}
}