大家好,今天我和大家分享一下文件的断点拷贝和分段拷贝。
文件的断点拷贝就是在文件拷贝的过程中因为某些原因突然中断拷贝,下次拷贝文件时能接着上次拷贝的位置拷贝。我们程序在运行过程如果遇到异常突然结束运行,那么这次程序运行的数据就会消失,想要实现文件的断点拷贝,就必须让程序运行的数据持久化保存,我们可以用文件来保存文件拷贝的位置。
文件的断点拷贝:RandomAccessFile类中提供了,seek()方法:让文件指针跳到指定的位置(下一次发生读写的位置);getFilePointer()方法:获取文件指针的位置。RandomAccessFile类的读写模式:r
以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 rw
打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 我们可以每次读写时记录文件拷贝的指针位置,即使突然中断拷贝,我们也知道了下次文件拷贝的起始位置,可以接着拷贝文件了。
try (
//需要读取的原始文件输入流
RandomAccessFile read = new RandomAccessFile("C:\\Users\\HP\\Desktop\\新建文件夹 (5)\\m.mp4", "r");
//需要拷贝到的目标文件的输出流
RandomAccessFile write = new RandomAccessFile("C:\\Users\\HP\\Desktop\\新建文件夹 (6)\\ok.mp4", "rw");
//记录文件拷贝位置的临时文件输入输出流
RandomAccessFile recordFile = new RandomAccessFile(
"C:\\Users\\HP\\Desktop\\新建文件夹 (6)\\position.txt", "rw");
) {
//记录起始的读写位置
long position = 0;
try {
//读取recordFile文件
recordFile.seek(0);
position = recordFile.readLong();
} catch (EOFException e) {
//如果没有recordFile文件,设置起始的读写位置为0
position = 0;
}
System.out.println("开始读写的位置:" + position);
//设置输入、输出流起始的读写位置
read.seek(position);
write.seek(position);
byte[] b = new byte[1024 * 1024];
int len = 0;
System.out.println("开始拷贝...");
while ((len = read.read(b)) != -1) {
write.write(b, 0, len);
//设置每次存储到recordFile文件的指针位置是起始位置
recordFile.seek(0);
//每次向recordFile文件中存储当前的文件读取的位置
recordFile.writeLong(read.getFilePointer());
}
System.out.println("拷贝完成!");
//清理recordFile文件
new File("C:\\Users\\HP\\Desktop\\新建文件夹 (6)\\position.txt").deleteOnExit();
} catch (IOException e) {
e.printStackTrace();
}
文件的分段拷贝就是把一个文件分成多段来拷贝。这个也是利用RandomAccessFile类来实现的,同时也用到了多线程。利用RandomAccessFile类中的seek()方法来设置每次读取的位置。
public class ThreadFileCopy extends Thread {
//需要拷贝的文件
private File source;
//目标文件
private File target;
//起始拷贝位置
private long start;
//结束拷贝位置
private long end;
public ThreadFileCopy(File source, File target, long start, long end) {
this.source = source;
this.target = target;
this.start = start;
this.end = end;
}
@Override
public void run() {
try ( //需要读取的原始文件输入流
RandomAccessFile in = new RandomAccessFile(source, "r");
//需要拷贝到的目标文件的输出流
RandomAccessFile out = new RandomAccessFile(target, "rw");
) {
//跳过指定个字节发生下一次读写操作
in.seek(start);
out.seek(start);
byte[] b = new byte[1024];
int len = 0;
//用于记录本条线程拷贝的总字节数
int total = 0;
System.out.println(getName() + "开始拷贝...");
while (((len = in.read(b)) != -1) && total < (end - start)) {
out.write(b, 0, len);
total += len;
}
System.out.println(getName()+"--->"+total);
System.out.println(getName() + "拷贝完成");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//需要拷贝的文件
File source = new File("C:\\Users\\HP\\Desktop\\新建文件夹 (5)\\m.mp4");
//目标文件
File target = new File("C:\\Users\\HP\\Desktop\\新建文件夹 (6)\\", source.getName());
//获取文件的总长度
long len = source.length();
//将文件分段获取每段长度
long item = len / 4;
for (int i = 0; i < 4; i++) {
//每次创建一个线程拷贝
ThreadFileCopy t = new ThreadFileCopy(source, target, i * item, (i + 1) * item);
t.setName("线程" + i);
//开启线程
t.start();
}
}
}