Java多线程复制大文件

时间:2022-01-11 17:18:34

复制大文件思路

将文件等分,分成n部分,交由n个线程去复制。
如何计算文件大小 File().length;

在进行文件写入时按照分块写入,所有必须规定fromFile,toFile,start,end;
其中fromFile为源文件,toFile为保存的文件
start为开始位置,end为结束位置。

主要使用的方法

写入读出设计到IO流,涉及到基础的IO操作
读入时要分块读入,涉及到 InputStream().skip();方法
写入需要分块,这里需要注意InputStream类没有相关跳过,或定位到指定位置,此时使用
RandomAccessFile类,其中see();可以相当于InputStream跳过skip方法。
剩下就按照普通的IO读取和写入进行相关操作。最后封装到线程中即可。

写在最后

在对文件的IO流进行直接操作,即传值时,需注意skip或seek操作的是同一对象。而不是不同对象。这里极有可能出错,所以传入对象为File,在其内部在获取到io流进行操作,即不会出错。
另对文件进行获取开始和结束时,需注意最后一块的大小。

贴上代码

主Test

public class MyTest {
public static void main(String[] args) {
IOTest ioTest = new IOTest();
String fileName="F:新东方词汇词根+联想记忆法MP3.rar";
ioTest.Test(5,fileName);
}


}

IOTest

import java.io.*;
import java.util.ArrayList;

public class IOTest {
public void Test(int time,String FileName) {
String fromPathName=FileName;
String toPathName=null;
OutputStream outputStream=null;
InputStream inputStream=null;
long length;
File fromfile=new File(fromPathName);
File tofile=null;
if (fromfile.exists()){
toPathName=fromfile.getParent()+"xindongfang\\"+fromfile.getName();
System.out.println("文件目录:\n"+toPathName);
}
tofile=new File(toPathName);
length=fromfile.length();//文件长度 假如5个线程同时往进写,所以length分成5分
System.out.println("多线程写入大文件啦 文件大小:"+length);
ArrayList<Node> arrayList=getNodeList(length,time);
/**
* 当一个父类目录存在时,当前文件不存在,打开io流时会自动创建对象
*/

try {
inputStream=new FileInputStream(fromPathName);
for (int i=0;i<time;i++){
new Thread(new IOThread(fromfile,arrayList.get(i).start,arrayList.get(i).end,tofile)).start();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
if (inputStream!=null){
try {
inputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}

}
}
private ArrayList getNodeList(long length,int time){
ArrayList<Node> arrayList=new ArrayList<>();
long split =length/time;
long start=0;
for (int i=0;i<time;i++){
if (i!=time-1){
arrayList.add(new Node(start,start+split-1));
start+=split;
}else {
arrayList.add(new Node(start,length-1));
}

//假设总数为100, 0-49 50-99
}
return arrayList;
}
class Node{
long start;
long end;

public Node(long start, long end) {
this.start = start;
this.end = end;
}
}
}

读取写入线程

import java.io.*;

public class IOThread implements Runnable {
InputStream inputStream = null;
long start;
long end;
RandomAccessFile outputStream;
File tofile = null;
File fromFile=null;
byte[] bytes = new byte[1024];

public IOThread(File fromFile, long start, long end, File toFile) {
this.start = start;
this.end = end;
this.fromFile=fromFile;
this.tofile=toFile;
}
int length;

@Override
public void run() {
try {
System.out.println("多线程读取开始了 开始: " + start + " 结束 :" + end + " 写入大小: " + (end - start + 1));

long sum = end - start + 1;

inputStream=new FileInputStream(fromFile);
outputStream=new RandomAccessFile(tofile,"rw");

inputStream.skip(start);
outputStream.seek(start);
while (sum>0) {

if (sum >= 1024) {
inputStream.read(bytes);
length=1024;
sum-=1024;
} else {
inputStream.read(bytes, 0, (int) sum);
length=(int)sum;
sum=0;
}
outputStream.write(bytes,0,length);
}


// outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}