/**
* FileName:RandomAccessFile.java
* @author zhanggw
* @date 2018年1月19日 下午7:42:43
*/
package com.kenick.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName RandomAccessFile
* @author zhanggw
* @date 2018年1月19日 下午7:42:43
*/
public class ThreadPoolWriteDemo {
public static int threadNum = 128; // 线程数
public static int cacheSize = 1024*1024*8; // 缓存8MB
public static long startTime; // 开始时间
public static int srcFileSize; // 原文件大小
public static ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
public static void main(String[] args) throws Exception{
String src = "D:/temp/bingxuebao.mp4"; // 复制原文件
String dst = "F:/temp/tmp17.mp4"; // 复制目标文件
startTime = System.currentTimeMillis(); // 开始时间
// 使用多线程复制文件
copy(src, dst, threadNum);
// 开启线程计算完成时间
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
if(executorService.isTerminated()){
long endTime = System.currentTimeMillis();
int fileSize = srcFileSize/1024/1024;
long spent = endTime - startTime;
System.out.println("文件总大小:"+fileSize+"MB");
System.out.println("花费时间:"+spent/1000+"秒,"+spent+"毫秒");
System.out.println("线程数:"+threadNum);
System.out.println("缓存大小:"+(cacheSize/1024/1024)+"MB");
if(spent/1000==0){
System.out.println("拷贝速度:"+(fileSize/spent)+"MB/毫秒");
}else{
System.out.println("拷贝速度:"+(fileSize/(spent/1000))+"MB/S");
}
break;
}
Thread.sleep(1); // 切换CPU
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
/**
* 使用threadNum个线程复制文件
*/
public static void copy(String src,String dst,int threadNum){
try {
// 获取原文件总大小
FileInputStream fileInputStream = new FileInputStream(src);
srcFileSize = fileInputStream.available();
fileInputStream.close();
// 获取每个线程需要复制的字节大小
int partSize = srcFileSize/threadNum;
// 目的文件夹如果不存在,则创建
File dstFile = new File(dst);
if(!dstFile.exists()){
dstFile.createNewFile();
}
// 启用threadNum个线程进行复制文件
for(int i=0;i<threadNum;i++){
int start = partSize * i;
int end = (i==(threadNum-1))?srcFileSize:partSize*(i+1);
executorService.execute(new Runnable() {
@Override
public void run() {
// 将src文件的start到end部分字节复制到dstFile中
copyByteToFile(src,start,end,dstFile);
}
});
}
// 关闭线程池,已提交的线程执行完毕后会自动结束
executorService.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将原文件复制到目的文件,通过字节划分
*/
@SuppressWarnings("resource")
public static void copyByteToFile(String src,int start,int end,File dstFile){
try {
String threadName = Thread.currentThread().getName(); // 线程名
System.out.println("线程"+threadName+"开始拷贝文件数据,拷贝数据段:"+start+"-"+end);
// 定位目标文件位置
RandomAccessFile randomAccessFile = new RandomAccessFile(dstFile, "rw");
randomAccessFile.seek(start);
// 定位原文件位置
InputStream inputStream = new FileInputStream(src);
inputStream = skipFully(inputStream,start);
// 复制文件内容
int sumSize = end - start; // 复制总字节数
int readSize = 1024*1024*8; // 缓存8MB
while(sumSize>0){
// 缓存大于拷贝字节,使用拷贝字节
if(readSize>sumSize){
readSize = sumSize;
}
// 从原文件输入流获取拷贝字节数据
byte[] tmp = new byte[readSize];
inputStream.read(tmp);
// 向目标文件写入拷贝字节数据
randomAccessFile.write(tmp);
sumSize -= readSize;
}
// 拷贝完毕后,双方都关闭
inputStream.close();
randomAccessFile.close();
System.out.println("线程"+threadName+"拷贝数据结束,数据段:"+start+"-"+end);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 修复inputstream.skip()缺陷,确保跳过输入流num个字节
*/
public static InputStream skipFully(InputStream in,long num)throws Exception{
long remainning = num;
long len = 0;
while(remainning>0){
len = in.skip(num);
remainning -= len;
}
return in;
}
}
ExecutorService线程池多线程分段拷贝文件。
最新推荐文章于 2022-05-07 09:53:43 发布