网上找了几个线程下载的例子,倒,没一个看懂的,还是自己写吧, 这个例子可以下载,拷贝文件和目录(支持断点续传) 保存以便以后重用.
package com.download.threads;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 多线程复制文件,多线程下载的例子
* @author 乔宇鹏
*/
public class ManyThreadReaderAndWriter {
private ThreadPoolExecutor threadPool ; //引用的线程池
private int minCount; //线程池最小线程数
private int maxCount; //线程池最大线程数
private int timeOut; //设置线程超时时间
private ExecuteWriteAndReadTarget target; //引用的任务
private boolean isOver; //标识任务是否完成
private InputStream readStream; //引用的读取流
private OutputStream writeStream; //引用的写入流
private Timer timer;
private long length;
public ManyThreadReaderAndWriter(int minCount,int maxCount,int timeout){
this.minCount = minCount;
this.maxCount = maxCount;
this.timeOut = timeOut;
this.threadPool = new ThreadPoolExecutor(minCount, maxCount, timeout,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
new ThreadPoolExecutor.DiscardOldestPolicy());
this.isOver = false;
this.length = 0L;
}
/**
* 多线程复制方法,若是文件,则调用copyFile方法,若是目录,则调用copyDirectory方法
* @param sourseFile 源文件
* @param targetFile 目标文件
* @param threadCount 使用的线程数
* @param cachSize 缓冲区大小
* @throws FileNotFoundException
*/
public void copy( File sourseFile ,File targetFile ,int threadCount,int cachSize ) throws FileNotFoundException{
if( sourseFile.isDirectory()) //若是目录
copyDirectory(sourseFile,targetFile,threadCount,cachSize);
else if( sourseFile.isFile()) //若是文件
copyFile(sourseFile,targetFile,threadCount,cachSize);
}
/**
* 多线程下载方法
* @param url 下载文件的url地址
* @param threadCount 线程数
* @param targetDir 本地保存目录
* @param cachSize 缓冲区大小
* @throws IOException
*/
public void down( URL url,int threadCount,File targetDir ,int cachSize ) throws IOException{
//获取连接,并保证连接可用
HttpURLConnection con = (HttpURLConnection) url.openConnection();
int repCode = con.getResponseCode();
if( repCode>=400 ){
System.out.println(" connect erro ");
return;
}
length = con.getContentLength();
//实例化输入输出流
readStream = con.getInputStream();
//创建本地目录下新文件对应的File对象,若存在,则删除
File newFile = new File(targetDir,subFileNameFromUrlStr(url.getFile()));
if( newFile.exists() ){
boolean isCanReget = isCanReget( newFile.length());
if( !isCanReget)
return;
}
writeStream = new BufferedOutputStream( new FileOutputStream( newFile,true));
//实例化任务对象
target = new ExecuteWriteAndReadTarget(writeStream,readStream,cachSize,length);
//启动多个线程去处理
for( int i=0; i<threadCount; i++ ){
threadPool.execute(target);
}
startTimer();
}
/**
* 从url中获取文件的名字
*/
private String subFileNameFromUrlStr(String file) {
String sub = file.substring(file.indexOf('/')+1);
if( sub.contains("/"))
return subFileNameFromUrlStr(sub);
else
return sub;
}
/**
* 多线程复制文件
*/
private void copyFile( File sourseFile, File targetDir, int threadCount ,int cachSize) throws FileNotFoundException{
length = sourseFile.length();
readStream = new BufferedInputStream( new FileInputStream(sourseFile));
writeStream = new BufferedOutputStream( new FileOutputStream( new File( targetDir,sourseFile.getName() )));
target = new ExecuteWriteAndReadTarget(writeStream,readStream,cachSize,length);
for( int i=0; i<threadCount; i++ )
threadPool.execute(target);
}
/**
* 多线程复制目录
*/
private void copyDirectory( File sourseDir,File targetDir, int threadCount ,int cachSize ) throws FileNotFoundException {
if( targetDir.isFile() )
throw new IllegalArgumentException("targetFile is not a dir");
getDirSize(sourseDir);
File newFile = new File(targetDir,sourseDir.getName());
newFile.delete();
newFile.mkdirs();
File[] files = sourseDir.listFiles();
for( File file : files){
if( file.isDirectory() )
copyDirectory(file,newFile,threadCount,cachSize);
else
copyFile(file,newFile,threadCount,cachSize);
}
}
/**
* 获取目录的大小
*/
private void getDirSize(File sourseDir) {
File[] files = sourseDir.listFiles();
for( File file : files){
if( file.isDirectory() )
getDirSize(file);
else if( file.isFile() )
this.length += file.length();
}
}
/**
* 关闭输入输出流
*/
public void closeStream() throws IOException{
if( readStream != null ) readStream.close();
if( writeStream != null ) writeStream.close();
}
/**
* 创建Timer监听器,监听任务完成状态
*/
public void startTimer(){
timer = new Timer(" Down Monitor ");
timer.schedule( new TimerTask(){
public void run() {
//输出任务完成百分比
double dividend = length;
double divider = 1024*1024;
BigDecimal b1 = new BigDecimal(dividend);
BigDecimal b2 = new BigDecimal(divider);
double showLength = b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println("length: "+showLength+"MB completed: "+(100*(target.complete))/length+"%");
//若读取完毕,则标识任务已完成,监听器结束监听
if( target.complete == length ){
isOver = true;
timer.cancel();
}
}
}, 0,3000);
}
/**
* 停止线程池
*/
public void threadPoolShutDown(){
threadPool.shutdownNow();
}
public boolean isOver(){
return isOver;
}
/**
* reget
* @throws IOException
*/
public boolean isCanReget( long exitsFileSize ) throws IOException{
if( exitsFileSize>=length ) {
System.out.println(" file exits ");
return false;
}
else {
length = length - exitsFileSize;
readStream.skip(exitsFileSize);
return true;
}
}
/**
* 负责读写任务的任务类
* @author 乔宇鹏
*
*/
class ExecuteWriteAndReadTarget implements Runnable {
private OutputStream writeStream;
private InputStream readStream;
private byte[] bytes;
public long complete;
private long length;
public ExecuteWriteAndReadTarget( OutputStream writeStream,InputStream readStream,int cachSize ,long length){
this.writeStream = writeStream;
this.readStream = readStream;
this.bytes = new byte[cachSize];
this.complete = 0;
this.length = length;
}
@Override
public void run() {
try {
boolean canRead = true;
do {
synchronized(this){
int c = readStream.read(bytes);
if( c > 0 ){
writeStream.write(bytes,0,c);
complete += c;
} else if( c == -1 ){
if( complete == length ){
canRead = false;
}
}
}
} while (canRead);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
下面是测试例子,下载了一个QQ音乐
package com.download.threads;
import java.io.File;
import java.net.URL;
public class Test {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
URL url = new URL("http://dl_dir.qq.com/music/clntupate/QQMusicV7.96.2062.0525.exe");
File targetFile = new File("d:/");
//
// System.out.println( url.openConnection().getContentLength() == targetFile.length());
//
// System.out.println( url.openConnection().getContentLength());
// System.out.println( targetFile.length());
// File sr = new File("F:/新建 Microsoft Office Word 2007 文档.docx");
// File t = new File("e:/");
ManyThreadReaderAndWriter mrw = new ManyThreadReaderAndWriter(30,100,10);
mrw.down(url, 15, targetFile, 10240);
long s = System.currentTimeMillis();
while( !mrw.isOver() ){}
long e = System.currentTimeMillis();
System.out.println("usetime: "+(e-s)/1000);
mrw.threadPoolShutDown();
mrw.closeStream();
// System.out.println( url.openConnection().getContentLength());
}
}