一、问题描述:已知目录下一个较大文件a.txt(内容4G大小),运用多线程将此文件内容拷贝的另一个目录下。
这次运用多线程来进行文件拷贝,大大节省了CPU的利用率,让程序变得更加高效。
二、思路
多线程处理这个问题,大概思路就是,将整个待拷贝文件内容分成若干等份(4G的 文件,分成4份),每个线程处理固定范围(1G)的内容,每个线程处理的范围起始位置,用IO中的随机访问类的seek()方法来确定;
- 主线程的作用:划分子线程读取的范围!
第一个线程读取0-1G: 0-length
第二个线程读取1G-2G: length+1…2length
第三个线程读取2G-3G: 2length…3length
第四个线程读取3G-4G: 3length…file.length(处理直到文件结尾的内容)
然后自定义子线程类,继承Thread,通过构造函数将四个参数传递给子线程:原位置,目的位置,开始读取的位置,读取的长度,在主线程内调用拷贝文件的函数
注: 如果文件内容不能等分成若干范围,则将最后剩余的部分,分给最后一个线程处理。这要在代码中体现出来。
三、代码展示
public class ThreadCopyDemo {
public static void main(String[] args) {
System.out.println("main thread start..."); //主线程开始
//定义源文件路径和目的路径
String srcpath = "C:\\Users\\50579\\Desktop\\a.txt";
String destpath = "C:\\Users\\50579\\Desktop\\b.txt";
MutilThreadCopyFile(srcpath,destpath,4);
System.out.println("main thread end..."); //主线程结束
}
public static void MutilThreadCopyFile(String srcPath,String destPath,Integer ThreadNum){
//参数校验
if(ThreadNum < 1){
return;
}
//文件划分
File file = new File(srcPath);
//获取文件长度
long length = file.length();
//计算子线程处理的长度
long len = length/ThreadNum;
// 创建并划分每个子线程所读的长度
for (int i = 0; i < ThreadNum-1; i++) {
SubThread subThread = new SubThread(srcPath, destPath, i * len, (i + 1) * len);
System.out.println("第"+i+"个子线程启动");
subThread.start();
System.out.println("第"+i+"个子线程结束");
}
//把剩余的分给最后一个线程
SubThread subThread = new SubThread(srcPath, destPath, ThreadNum * len, file.length());
System.out.println("lastThread start...");
subThread.start();
System.out.println("lastThread end...");
}
}
//自定义子线程类 继承Thread
class SubThread extends Thread{
private String srcPath;
private String destPath;
private long startIndex;
private long endIndex;
//构造函数:
public SubThread(String srcPath,String destPath,long startIndex,long endIndex){
this.srcPath = srcPath;//源文件路径
this.destPath = destPath;//目的路径
this.startIndex = startIndex;//开始位置
this.endIndex = endIndex;//结束位置
}
@Override
public void run() { //子线程操作
//随机访问类读取源文件,通过seek()方法将指针移到固定位置,将读取的内容写入目的文件
try {
RandomAccessFile srcFile = new RandomAccessFile(srcPath,"r"); //源文件,只读
RandomAccessFile destFile = new RandomAccessFile(destPath, "rw"); //目的文件,读写
//指针移到指定位置
srcFile.seek(startIndex);
destFile.seek(startIndex);
long index = startIndex; //标志读取的起始位置
byte[] bytes = new byte[1000]; //读取内容到数组
int n;
while ((n = srcFile.read(bytes)) != -1){//读到文件结尾
index+=n; //更新读取的位置
destFile.write(bytes,0,n); //将读的数组写入目的路径
if(index >= endIndex){ //读到当前线程的范围结尾处
break;
}
}
srcFile.close();//关闭流
destFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、执行结果
这是原文件a.txt的内容
b.txt可有可无,因为随机访问类在写入的时候,会先判断文件是否存在,不存在则新建一个。
然后运行程序,
点开b.txt文件,内容就被复制过来了