方法一、由n个线程完成一个文件的复制,即每个线程负责文件长度/n的一部分
若文件长度为len,由n个线程完成
线程1–读写从0到len/n
线程2–读写从2(len/n)-len/n
…..
最后一个线程–读写从len-(n-1)(len/n)
以下为代码实现部分:
一、利用RadomAccessFile作为输出流
public class MyThread implements Runnable {
// 读取文件的起始位置
private int start, end;
// 源文件路径和目标文件路径
private String scr, des;
// 利用构造方法传入初始值
public MyThread(int start, int end, String scr, String des) {
super();
this.start = start;
this.end = end;
this.scr = scr;
this.des = des;
}
@Override
public void run() {
File f1 = new File(scr);
File f2 = new File(des);
try {
InputStream input = new FileInputStream(f1);
// 由于RandomAccessFile通过seek()方法可以指定输出的位置,因此选择它作为输出流
RandomAccessFile out = new RandomAccessFile(f2,"rw");
// 线程跳过的数据
int t = (int)input.skip(start);
//输出的位置
out.seek(start);
// 读取每一段文件的数据
int count = 0;
while (count++ <= (end - t)) {
int a = (byte)input.read();
out.write(a);
}
input.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//主函数
public class Main {
public static void main(String[] args) {
// 源文件路径
String scr = "/Users/wangjue/Documents/java实战入门.pdf";
// 目标文件路径
String des = "/Users/wangjue/Documents/java实战入门(1).pdf";
File f = new File(scr);
long len = f.length();// 获取文件长度
// 假设将文件交个3个进程处理
int count = 3;
int num = (int) len / count;
// 创建并启动前两个线程
for (int i = 0; i < count - 1; i++) {
new Thread(new MyThread(num * i, num * (i + 1), scr, des)).start();
}
// 创建并启动最后一个线程
new Thread(new MyThread(2 * num, (int) len, scr, des)).start();
long t2 = System.currentTimeMillis();
}
}
二、输出流输出入流都选择RandomAccessFile,使用文件通道,即FileChannel进行处理时,一定要注意同步问题。
在jdk对于FileChannle有以下解释:
对于涉及通道位置或者可以更改其文件大小的操作,在任意给定时间只能进行一个这样的操作;如果尝试在第一个操作仍在进行时发起第二个操作,则会导致在第一个操作完成之前阻塞第二个操作。
以下为代码实现:
public class CopyThread implements Runnable {
private String srcPath;
private String destPath;
private int start, end;
public CopyThread(String srcPath, String destPath, int start, int end) {
super();
this.srcPath = srcPath;
this.destPath = destPath;
this.start = start;
this.end = end;
}
@Override
public void run() {
try {
RandomAccessFile in = new RandomAccessFile(srcPath, "r");
RandomAccessFile out = new RandomAccessFile(destPath, "rw");
// 将输入跳转到指定位置
in.seek(start);
// 从指定位置开始写
out.seek(start);
// 获取文件管道
FileChannel fin = in.getChannel();
FileChannel fout = out.getChannel();
//对输出流锁定
FileLock lock = fout.lock(start, end-start, false);
// 将通道的文件传输到给定的可写入字节通道
fin.transferTo(start, end - start, fout);
//释放锁
lock.release();
in.close();
out.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//主函数
package 多线程复制文件;
import java.io.File;
public class Main {
public static void main(String[] args) {
String srcPath = "/Users/wangjue/documents/Java实战入门.pdf";
String destPath = "/Users/wangjue/documents/Java实战入门(1).pdf";
//获得源文件长度
File f = new File(srcPath);
long len = f.length();
int count = 3;//需要的线程数
int oneNum = (int)len/count;
for(int i=0;i<count-1;i++) {
CopyThread ct = new CopyThread(srcPath, destPath, oneNum*i, oneNum*(i+1));
new Thread(ct).start();
}
CopyThread ct2 = new CopyThread(srcPath, destPath, oneNum*2, (int)len);
new Thread(ct2).start();
}
}