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

主要思路

对应下面第一 部分代码
     之所以要多线程拷贝文件,为的就是提高拷贝的效率,所以要把一个文件均分给每一个线程一部分,但是文件不一定就能刚好被均分,所以最后一个线程就要多接收余下的那一部分内容。(这就要求可以给每个线程的开始和结束位置定位,完成了指定内容则关闭该线程,所以需要使用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();
			}
		}
		
	}
}

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

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值