一、问题描述:已知目录下一个较大文件a.txt(内容4G大小),运用多线程将此文件内容拷贝的另一个目录下。

这次运用多线程来进行文件拷贝,大大节省了CPU的利用率,让程序变得更加高效。

二、思路

多线程处理这个问题,大概思路就是,将整个待拷贝文件内容分成若干等份(4G的 文件,分成4份),每个线程处理固定范围(1G)的内容,每个线程处理的范围起始位置,用IO中的随机访问类的seek()方法来确定;

  • 主线程的作用:划分子线程读取的范围!
    第一个线程读取0-1G: 0-length
    第二个线程读取1G-2G: length+1…2length
    第三个线程读取2G-3G: 2length…3length
    第四个线程读取3G-4G: 3
    length…file.length(处理直到文件结尾的内容)
    然后自定义子线程类,继承Thread,通过构造函数将四个参数传递给子线程:原位置,目的位置,开始读取的位置,读取的长度,在主线程内调用拷贝文件的函数

注: 如果文件内容不能等分成若干范围,则将最后剩余的部分,分给最后一个线程处理。这要在代码中体现出来。

三、代码展示

public class ThreadCopyDemo {
    public static void main(String[] args)  { 
        System.out.println("main thread start...");  //主线程开始
        //定义源文件路径和目的路径
        String srcpath = "C:\\Users\\50579\\Desktop\\a.txt"; 
        String destpath = "C:\\Users\\50579\\Desktop\\b.txt";

        MutilThreadCopyFile(srcpath,destpath,4);
         
        System.out.println("main thread end..."); //主线程结束
    }


    public static void MutilThreadCopyFile(String srcPath,String destPath,Integer ThreadNum){
        //参数校验
        if(ThreadNum < 1){
            return;
        }

        //文件划分
        File file = new File(srcPath);
        //获取文件长度
        long length = file.length();
        //计算子线程处理的长度
        long len = length/ThreadNum;

        // 创建并划分每个子线程所读的长度
        for (int i = 0; i < ThreadNum-1; i++) {
            SubThread subThread = new SubThread(srcPath, destPath, i * len, (i + 1) * len);
            System.out.println("第"+i+"个子线程启动");
            subThread.start();
            System.out.println("第"+i+"个子线程结束");
        }
        //把剩余的分给最后一个线程
        SubThread subThread = new SubThread(srcPath, destPath, ThreadNum * len, file.length());
        System.out.println("lastThread start...");
        subThread.start();
        System.out.println("lastThread end...");

    }
}
//自定义子线程类   继承Thread
class SubThread extends Thread{
    private String srcPath; 
    private String destPath;
    private long startIndex;
    private long endIndex;
    //构造函数:
    public SubThread(String srcPath,String destPath,long startIndex,long endIndex){
        this.srcPath = srcPath;//源文件路径
        this.destPath = destPath;//目的路径
        this.startIndex = startIndex;//开始位置
        this.endIndex = endIndex;//结束位置
    }


    @Override
    public void run() {  //子线程操作
        //随机访问类读取源文件,通过seek()方法将指针移到固定位置,将读取的内容写入目的文件
        try {
            RandomAccessFile srcFile = new RandomAccessFile(srcPath,"r");  //源文件,只读
            RandomAccessFile destFile = new RandomAccessFile(destPath, "rw"); //目的文件,读写

            //指针移到指定位置
            srcFile.seek(startIndex);
            destFile.seek(startIndex);

            long index = startIndex; //标志读取的起始位置
            
            byte[] bytes = new byte[1000]; //读取内容到数组 
            
            int  n;
            while ((n = srcFile.read(bytes)) != -1){//读到文件结尾

                index+=n; //更新读取的位置

                destFile.write(bytes,0,n); //将读的数组写入目的路径

                if(index >= endIndex){  //读到当前线程的范围结尾处
                    break;
                }
            }
            srcFile.close();//关闭流
            destFile.close();

        }  catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、执行结果

这是原文件a.txt的内容

Java 小文件复制 java复制大文件_子线程


b.txt可有可无,因为随机访问类在写入的时候,会先判断文件是否存在,不存在则新建一个。

然后运行程序,

Java 小文件复制 java复制大文件_System_02


点开b.txt文件,内容就被复制过来了

Java 小文件复制 java复制大文件_子线程_03