多线程下载,拷贝文件java代码

网上找了几个线程下载的例子,倒,没一个看懂的,还是自己写吧, 这个例子可以下载,拷贝文件和目录(支持断点续传) 保存以便以后重用.

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());
	}
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值