java 线程池复制文件

需求:

    使用多(3个以上)线程(可以选择使用线程池)将D盘一个大文件(找一个超过500M的文件),复制到E盘。 使用RandomAccessFile实现。
 最后一个线程结束后 后显示复制后的文件的文件路径!并提示复制完成!

代码:

package com.hcq.day24;

import java.io.File;

import com.hcq.day24.FileDownloadUtils.OnDownloadListener;

/**
 * 使用多(3个以上)线程(可以选择使用线程池)将D盘一个大文件(找一个超过500M的文件),复制到E盘。 使用RandomAccessFile实现。
 * 最后一个线程结束后 后显示复制后的文件的文件路径!并提示复制完成!
 * 
 * @author Administrator
 *
 */
public class Main {

	public static void main(String[] args) {
		File from = new File("D:/test.zip");
		File to = new File("E:/");
 
		FileDownloadUtils.downLoad(from, to, new OnDownloadListener() {

			public void onComplete(File file) {
				System.out.println("复制完成!");
				System.out.println(file);
			}

			public void onProgress(int progress) {
				System.out.println(progress + "%");
			}

		});
	}

}

package com.hcq.day24;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class FileDownloadUtils {
	private static final int LOAD_NUM = 3;// 同时下载的线程数
	private static ThreadPoolExecutor executor;// 线程池
	private static final int sums[];// 记录每个线程下载的进度
	private static OnDownloadListener listener = null;
	private static int lastProgress = 0;// 记录上一个进度百分点
	private static int index = 0;
	static {
		sums = new int[LOAD_NUM];
		// 创建线程池
		executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(LOAD_NUM);
		executor.prestartAllCoreThreads();// 预加载线程
		// executor.setKeepAliveTime(1, TimeUnit.MICROSECONDS);
		// executor.allowCoreThreadTimeOut(true);
	}
	private static File dest;// 粘贴 的目标文件
	private static long fileLength;// 复制的文件总长度
	// url>>>D:/A/test.zip
	// dir>>>E:/B/E
	// dest>>E:/B/E/test.zip

	public static void downLoad(File url, File dir, OnDownloadListener l) {
		FileDownloadUtils.listener = l;// 回调函数
		final File src = url;
		fileLength = src.length();
		dest = new File(dir, src.getName());// 目标文件路径描述的对象
		setTemporaryFile(dest, src.length());// 开辟临时文件
		long start = 0;
		long end = 0;
		for (int i = 0; i < LOAD_NUM; i++) {
			start = end;
			if (i == LOAD_NUM - 1) {
				end = fileLength;
			} else {
				end = start + fileLength / LOAD_NUM;
			}
			LoadWorker loadWorker = new LoadWorker(src, dest, start, end, i);
			executor.execute(loadWorker);// 执行多线程,并开始下载
		}

	}

	/**
	 * 完成下载。
	 */
	private static synchronized void loadComplete() {
		index++;
		if (index >= LOAD_NUM) {
			// 下载完成啦...
			if (listener != null) {
				listener.onComplete(dest);
				index = 0;
			}
		}
	}

	/**
	 * 监听函数 的标准协议。
	 *
	 */
	public interface OnDownloadListener {
		void onComplete(File file);// 文件下载完成通知

		void onProgress(int progress);// 下载进度通知
	}

	/**
	 * 设置临时文件
	 * 
	 * @param file
	 */
	private static void setTemporaryFile(File file, long length) {
		try (RandomAccessFile raf = new RandomAccessFile(file, "rw");) {
			raf.setLength(length);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 进度计算
	 */
	private static void progress() {
		// 进度变化啦》。。
		if (listener != null) {
			long sunLength = 0;
			for (int i : sums) {
				sunLength += i;
			}
			// 当前进度百分点
			int progress = (int) (100.0 * sunLength / fileLength);
			if (progress > lastProgress) {// 当百分点发生变化,则通知接口回调
				// 防止多个线程同事 刷新同一个百分点
				synchronized (FileDownloadUtils.class) {
					// 双重验证
					if (progress > lastProgress) {// 通知进度
						listener.onProgress(progress);// 记录上一个百分点
						lastProgress = progress;
					}
				}
			}
		}
	}

	private static class LoadWorker implements Runnable {
		private File src;// 拷贝的文件
		private File dest;// 粘贴的文件
		private long start;// 当前线程开始下载的位置
		private long end;// 当前线程结束下载的位置
		private int index = 0;// 记录该线程的编号,为了记录进度

		public LoadWorker(File src, File dest, long start, long end, int index) {
			super();
			this.src = src;
			this.dest = dest;
			this.start = start;
			this.end = end;
			this.index = index;
		}

		@Override
		public void run() {
			try (RandomAccessFile from = new RandomAccessFile(src, "r");
					RandomAccessFile to = new RandomAccessFile(dest, "rw");) {

				from.seek(start);
				to.seek(start);
				byte[] b = new byte[1024];
				int len = b.length;
				int sum = 0;
				while (true) {
					long poor = (end - start) - sum;
					if (poor < b.length) {
						len = (int) poor;
					}
					int read = from.read(b, 0, len);
					to.write(b, 0, read);
					sum += read;
					sums[index] = sum;// 记录当前线程的下载进度
					progress();// 更新进度
					if (sum >= end - start) {
						// 当前线程读取完毕
						loadComplete();
						break;
					}
				}

			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

}


截图:

java 线程池复制文件_第1张图片

你可能感兴趣的:(javaSE)