ExecutorService线程池多线程分段拷贝文件。

/**
 * FileName:RandomAccessFile.java
 * @author zhanggw
 * @date 2018年1月19日 下午7:42:43
 */
package com.kenick.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName RandomAccessFile
 * @author zhanggw
 * @date 2018年1月19日 下午7:42:43
 */
public class ThreadPoolWriteDemo {
    public static int threadNum = 128; // 线程数
    public static int cacheSize = 1024*1024*8; // 缓存8MB
    public static long startTime;  // 开始时间
    public static int srcFileSize;  // 原文件大小
    public static ExecutorService executorService = Executors.newFixedThreadPool(threadNum); 
    
    public static void main(String[] args) throws Exception{
        String src = "D:/temp/bingxuebao.mp4"; // 复制原文件
        String dst = "F:/temp/tmp17.mp4"; // 复制目标文件
        startTime = System.currentTimeMillis(); // 开始时间
        
        // 使用多线程复制文件
        copy(src, dst, threadNum);
        
        // 开启线程计算完成时间
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        if(executorService.isTerminated()){
                            long endTime = System.currentTimeMillis();
                            int fileSize = srcFileSize/1024/1024;
                            long spent = endTime - startTime;
                            System.out.println("文件总大小:"+fileSize+"MB");
                            System.out.println("花费时间:"+spent/1000+"秒,"+spent+"毫秒");
                            System.out.println("线程数:"+threadNum);
                            System.out.println("缓存大小:"+(cacheSize/1024/1024)+"MB");
                            if(spent/1000==0){
                                System.out.println("拷贝速度:"+(fileSize/spent)+"MB/毫秒");            
                            }else{
                                System.out.println("拷贝速度:"+(fileSize/(spent/1000))+"MB/S");                                
                            }
                            break;
                        }
                        Thread.sleep(1); // 切换CPU
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
    
    /**
     * 使用threadNum个线程复制文件
     */
    public static void copy(String src,String dst,int threadNum){
        try {
            //  获取原文件总大小
            FileInputStream fileInputStream = new FileInputStream(src);
            srcFileSize = fileInputStream.available();
            fileInputStream.close();
            
            // 获取每个线程需要复制的字节大小
            int partSize = srcFileSize/threadNum;
            
            // 目的文件夹如果不存在,则创建
            File dstFile = new File(dst);
            if(!dstFile.exists()){
                dstFile.createNewFile();
            }
            
            // 启用threadNum个线程进行复制文件
            for(int i=0;i<threadNum;i++){
                int start = partSize * i;
                int end = (i==(threadNum-1))?srcFileSize:partSize*(i+1);
                
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        // 将src文件的start到end部分字节复制到dstFile中
                        copyByteToFile(src,start,end,dstFile);
                    }
                });
            }
            
            // 关闭线程池,已提交的线程执行完毕后会自动结束
            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 将原文件复制到目的文件,通过字节划分
     */
    @SuppressWarnings("resource")
    public static void  copyByteToFile(String src,int start,int end,File dstFile){
        try {
            String threadName = Thread.currentThread().getName(); // 线程名
            System.out.println("线程"+threadName+"开始拷贝文件数据,拷贝数据段:"+start+"-"+end);
            
            // 定位目标文件位置
            RandomAccessFile randomAccessFile = new RandomAccessFile(dstFile, "rw");
            randomAccessFile.seek(start);
            
            // 定位原文件位置
            InputStream inputStream = new FileInputStream(src);
            inputStream = skipFully(inputStream,start); 
            
            // 复制文件内容
            int sumSize = end - start; // 复制总字节数
            int readSize = 1024*1024*8; // 缓存8MB
            while(sumSize>0){
                //  缓存大于拷贝字节,使用拷贝字节
                if(readSize>sumSize){
                    readSize = sumSize;
                }
                
                // 从原文件输入流获取拷贝字节数据
                byte[] tmp = new byte[readSize];
                inputStream.read(tmp);
                
                // 向目标文件写入拷贝字节数据
                randomAccessFile.write(tmp);
                sumSize -= readSize;
            }
            
            // 拷贝完毕后,双方都关闭
            inputStream.close();
            randomAccessFile.close();
           
            System.out.println("线程"+threadName+"拷贝数据结束,数据段:"+start+"-"+end);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     *  修复inputstream.skip()缺陷,确保跳过输入流num个字节
     */
    public static InputStream skipFully(InputStream in,long num)throws Exception{
        long remainning = num;
        long len = 0;
        while(remainning>0){
            len = in.skip(num);
            remainning -= len;
        }
        return in;
    }
}

猜你喜欢

转载自blog.csdn.net/leadseczgw01/article/details/79115971
今日推荐