java 利用 RandomAccessFile 多线程 上传文件

package com.xin.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class StepWriteFile {
    /**
     * 需要读取的目标文件
     */
    private String source;
    /**
     * 将文件写入到具体的目标位置
     */
    private String target;
    /**
     * 单个分片的大小
     */
    private Long size;
    /**
     * 文件
     */
    private File file;


    private Long readTotal=0L;




    /**
     * 记录当前写入到文件的哪个位置了
     */
    private Long writeSeek = 0L;

    private ExecutorService executorService;

    public StepWriteFile(String source, String target,Long size) {
        this.source = source;
        this.target = target;
        this.size=size;
        executorService = Executors.newFixedThreadPool(6);
        this.file = new File(source);
    }

    /**
     * 分片详情信息
     */
    class Slice implements Comparable<Slice>{
        /**
         * 分片的第几部分
         */
        private Integer sort;
        /**
         * 分片字节数组
         */
        private byte[] bytes;
        /**
         * 本次读取的大小
         */
        private Integer readSize;
        /**
         * 当前分片是从哪一个位置开始读取的
         */
        private Long readSeek =0l;

        @Override
        public int compareTo(Slice o) {
           return this.sort-o.sort;
        }
    }

    /**
     * 分片读取文件的任务类
     */
    class ReadFileTask implements Callable<Boolean>{

        private List<Slice> fileList;

        private RandomAccessFile targetFile;

        private CountDownLatch countDownLatch;
        public ReadFileTask(List<Slice> fileList, RandomAccessFile targetFile,CountDownLatch countDownLatch) {
            this.fileList = fileList;
            this.targetFile = targetFile;
            this.countDownLatch=countDownLatch;
        }

        @Override
        public Boolean call() throws Exception {
           try {
               byte[] bytes = null;
               //如果当前还支持创建一个预定义分区大小的字节数组
               if (file.length()-readTotal>=size){
                   bytes= new byte[Math.toIntExact(size)];
               }
               else {
                   bytes=new byte[(int) (file.length()-readTotal)];
               }
               Slice slice = new Slice();
               synchronized ("suo"){
                   readTotal+=bytes.length;
                   targetFile.seek(readTotal-bytes.length);
                   slice.sort= Math.toIntExact(readTotal - bytes.length);
                   slice.readSeek=readTotal-bytes.length;
               }
               int read = targetFile.read(bytes);
               synchronized ("锁"){
                   System.out.println("读取的文件大小\t"+read);
                   slice.readSize=read;
                   slice.bytes=bytes;
                   fileList.add(slice);
                   countDownLatch.countDown();
               }
               return true;
           }catch (Exception e){
               e.printStackTrace();
               System.out.println("出现了异常");
               return false;
           }
        }
    }

    /**
     * 根据每个分片读取的文件大小,计算出一共需要几条线程
     * @return
     */
    private Integer getThreadCount(){
        long length = this.file.length();
        if (length%size==0) {
            return Math.toIntExact(length / size);
        }
        return Math.toIntExact(length/size+1);
    }

    /**
     * 上传文件
     * @return
     */
    public boolean uploadFile() throws InterruptedException, IOException {
        //该文件一共需要几条线程进行上传
        Integer threadCount = this.getThreadCount();
        //读取文件获取每个文件段的文件内容
        List<Slice> sliceList = this.readFileToList(threadCount);
        //将文件内容上传到指定目录
        RandomAccessFile randomAccessFile = new RandomAccessFile(target,"rw");
        return this.writeFileToTarget(sliceList,randomAccessFile);
    }

    /**
     * 读取文件到list集合中
     * @return
     */
    private List<Slice> readFileToList(Integer threadCount) throws InterruptedException, FileNotFoundException {
        List<Slice> list = new LinkedList<>();
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        List<Callable<Boolean>> callableList = new LinkedList<>();
        for (int i = 0; i < threadCount; i++) {
            RandomAccessFile randomAccessFile = new RandomAccessFile(source,"rw");
            ReadFileTask readFileTask  = new ReadFileTask(list,randomAccessFile,countDownLatch);
            callableList.add(readFileTask);
        }
        executorService.invokeAll(callableList);
        countDownLatch.await();
        return list;
    }
    /*
    *  Long totalSize = 0L;
        for (Slice slice : sliceList) {
            randomAccessFile.write(slice.bytes);
            totalSize+=slice.readSize;
            randomAccessFile.seek(totalSize);
        }
        randomAccessFile.close();
    * */
    /**
     * 将文件上传到指定目录位置
     * @param sliceList
     * @param randomAccessFile
     * @return
     */
    private boolean writeFileToTarget(List<Slice> sliceList,RandomAccessFile randomAccessFile) throws InterruptedException, IOException {
        System.out.println("开始写文件开始写文件");

        Collections.sort(sliceList);

        for (Slice slice : sliceList) {
            randomAccessFile.seek(slice.readSeek);
            randomAccessFile.write(slice.bytes);
        }
        executorService.shutdownNow();
        System.out.println("文件写入成功");
        return true;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值