作业题:使用多个线程复制同一份文件,每个线程仅复制文件的一部分

作业题:使用多个线程复制同一份文件,每个线程仅复制文件的一部分

思路:

1.首先获取文件的长度,设置线程数,并计算出每个线程平均应该复制的文件大小

2.计算出每个线程复制的起始位置和终止位置

long start = pj * i;
long end = (i + 1) * pj - 1;

3.当文件的大小不能够平均分配时,此时应该再补一个线程,计算出这个线程复制剩余部分文件的起始位置和终止位置

long start = threadNum * pj;
long end = totalLength;

4.开始复制文件,应该使用RandomAccessFile流,使用读写模式,并设置文件读取指针到起始位置

in.seek(start);
out.seek(start);

5.在进行复制文件的时候,因为每个线程只负责一部分文件的赋值,故在复制的时候应该判断start < end,当条件不满足的时候,就不再读取和复制文件

代码:

public class MyTest {
    public static void main(String[] args) throws FileNotFoundException {
        File srcFile = new File("辛晓琪 - 领悟.mp3");
        //获取文件的总大小
        long totalLength = srcFile.length();
        //定义线程的数量
        long threadNum =3;
        //计算机每个线程平均要复制的字节大小
        long pj = totalLength / threadNum;

        //我们得计算每个线程复制的那部分字节数据的起始位置和结束位置
        for (long i = 0; i < threadNum; i++) {
            long start = pj * i;
            long end = (i + 1) * pj - 1;
            //System.out.println("线程"+i+"起始位置:"+start+"结束位置:"+end);
            //开启线程复制
            new CopyFileThread(start, end, srcFile, new File("E:\\领悟.mp3")).start();
        }
      
        //如果不够均分,我就在补一个线程,把剩下的复制完
        if (totalLength % threadNum != 0) {
            System.out.println("不均分");
            long start = threadNum * pj;
            long end = totalLength;
            new CopyFileThread(start, end, srcFile, new File("E:\\领悟.mp3")).start();
        }
    }
}
class CopyFileThread extends Thread {
    private long start;
    private long end;
    private RandomAccessFile in;
    private RandomAccessFile out;

    /**
     * @param start      每个线程复制的起始位置
     * @param end        每个线程复制的结束位置
     * @param srcFile    源文件
     * @param targetFile 目标文件
     */

    public CopyFileThread(long start, long end, File srcFile, File targetFile) throws FileNotFoundException {
        this.start = start;
        this.end = end;
        in = new RandomAccessFile(srcFile, "rw");
        out = new RandomAccessFile(targetFile, "rw");
    }


    @Override
    public void run() {
        try {
            //设置每个线程开始读写的位置
            in.seek(start);
            out.seek(start);
            int len = 0;
            byte[] bytes = new byte[1024*8];        
            while (start < end && (len = in.read(bytes)) != -1) {
                start += len;
                out.write(bytes, 0, len);
            }
            in.close();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里注意,还有一个问题:

如果采用一次读取一个字节数组的方式来复制文件,会出现即使我们把最后一个线程复制文件的终止位置-1,也能将全部的字节复制,原因是因为缓冲区不是一个字节 start < end 只是逻辑上隔离了,实际上,上一个线程可能在不是最终刚好剩余的待复制的字节数等于字节数组的长度,故在最后一次复制的时候,还会覆盖到下一个线程应该复制的字节,故即使我们把最后一个线程复制的终止位置-1,也不会影响最后文件的复制。

但是如果采用一个一个字节复制的方式,start < end 就会隔离了 此时如果把最后一个线程复制的终止位置-1,最后复制的文件字节数也会少1.

你可能感兴趣的:(java,SE)