【线程】多线程同时拷贝同一文件

时间:2021-12-27 10:07:01

主要思路

对应下面第一 部分代码     之所以要多线程拷贝文件,为的就是提高拷贝的效率,所以要把一个文件均分给每一个线程一部分,但是文件不一定就能刚好被均分,所以最后一个线程就要多接收余下的那一部分内容。(这就要求可以给每个线程的开始和结束位置定位,完成了指定内容则关闭该线程,所以需要使用RandomAccessStream这个随机流里的定位方法【seek(long pos)】)。 而开始拷贝之前,为了能定位需要,创建一个新的文件,大小跟要拷贝的文件一致,这样才能用seek来定位(拷贝时两个文件都得定位)。 以上都是开始运行线程前的准备工作。 对应下面第二部分代码 下面开始说明如何在拷贝方法中判断是否完成任务: 首先读取原文件的时候为了快速,我们必然会用读byte[]数组的方法,根据文件的大小我们可以调整byte数组的大小。那么接下来就是重点-判断:首先要定义一个整形变量在读取内容的while循环之外,在循环中该变量自增,当变量增长到和数组应传入的次数相同时(整形变量=该线程应copy的大小/byte[]大小),进行判断是否能整除,若能整除直接跳出循环,流也就自动关闭,若不能整除,则要把余下未传入的值,传输完成(未传入值的大小=该线程应copy的大小%byte[]大小),然后跳出循环,线程自动关闭。  

第一部分代码

import java.io.*;
/**
*类名: DonwLoadMain
*功能:copy的主函数
*作者:杨靖罡
*时间:2017年8月13日上午9:09:30
*/
public class DonwLoadMain {

public static void main(String[] args) {
File source=new File("G:\\movie\\one.mkv");
File target=new File("E:\\mov\\测试下载速度资源1.mp4");

/**
* 准备阶段,先得到一个跟原文件 内容一一对应的文件(其中内容都是0 其他其实也不影响 )
* 因为只有这样,才能使用定位的 【 .seek() 方法】来写入文件中的内容
* 这就是为什么每次迅雷下载的时候,在一开始就会出现一个 无法打开但是大小是要下载文件大小的文件
* 这就是多线程下载的一部分内容
*/
BufferedOutputStream bos=null;

try {
bos=new BufferedOutputStream(new FileOutputStream(target));
long size=source.length();
byte b[]=new byte[1024*1024];
for (int i = 0; i < size/(1024*1024); i++) {
bos.write(b);
}
bos.flush();
if(size%(1024*1024)!=0) {
bos.write(new byte[(int)(size%(1024*1024))]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}finally {
try {
if(bos!=null)bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}

//可以开始传输文件
/*
* 这里也很关键,一个一个来new新的线程就太费劲了
* 需要使用for循环,那么这里的start 和 end 的变化就很关键了
*
* */
//首先 建立一个线程数组 只有这样才能在 for 中得到多个线程

// 这里面就牵扯到是否他们的值可以放的完,如果能刚好放完还好,若放不完
//就需要考虑再最后补进,所以让第最后一个线程多放一点,多了一点余数,所以for里面只创建99个线程

DonwLoadThread download[]=new DonwLoadThread[100];
long size=source.length()/100;
for (int i = 0; i < download.length-1; i++) {
download[i]=new DonwLoadThread((i*size), ((i+1)*size-1), source, target);
download[i].start();

}
download[99]=new DonwLoadThread(99*size, source.length()-1, source, target);
download[99].start();
}

}

第二部分代码

import java.io.*;
/**
*类名: DonwLoadTool
*功能: 下载的方法
*作者:杨靖罡
*时间:2017年8月12日下午4:41:10
*/
public class DonwLoadTool {
private File source;
private File target;
public DonwLoadTool(File score, File target) {
this.source = score;
this.target = target;
}
// 因为需要定位所以要使用Random方法来 读取和写入

/**
* 这里很关键,这段代码是能否高copy的关键
* @param str 起始拷贝位置
* @param end 拷贝结束位置
*/
public void copy(long str,long end) {
RandomAccessFile r=null;
RandomAccessFile w=null;

try {
w=new RandomAccessFile(target, "rw");
r=new RandomAccessFile(source, "r");

r.seek(str);
w.seek(str);
int x=-1;
byte b[]=new byte[1024*1024];
int number=0;
while ((x=r.read(b))!=-1) {
w.write(b, 0, x);
number++;
if(((int)(end-str)/(1024*1024))==number) {
if((end-str)%(1024*1024)!=0) {
byte b1[]=new byte[(int) ((end-str)%(1024*1024))];
int last=r.read(b1);
w.write(b1, 0, last);
}

break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
} finally {
try {
if(w!=null)w.close();
if(r!=null)r.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
}

以上就是我对多线程拷贝一个文件的理解