• 大文件RandomAccessFile类来分片传输


    RandomAccessFile简单使用

        /**
         * @param :
         * @return void
         * @author Ladidol
         * @description 文件的续写.
         * @date 2022/6/30 14:35
         */
        @Test
        public void fileContinue() {
    
            File preFile = new File("D:\\randomaccessfiletest\\pre.txt");
            File endFile = new File("D:\\randomaccessfiletest\\end.txt");
    
    
            try (
                    RandomAccessFile r = new RandomAccessFile(endFile, "r");
                    RandomAccessFile w = new RandomAccessFile(preFile, "rw");
            ) {
    
                w.seek(w.length()); // 将指针指向文件最后,进行追加
                byte[] bytes = new byte[1024];
                int len = -1;
                while ((len = r.read(bytes)) != -1) {
                    w.write(bytes);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    大文件单线程直接传输

        /**
         * @param :
         * @return void
         * @author Ladidol
         * @description 单线程文件读写. 耗时长, 且主线程堵塞.
         * @date 2022/6/29 21:03
         */
        @Test
        public void fileReadAndWrite() throws IOException {
            //开始传输时间
            long start = System.currentTimeMillis();
            File preFile = new File("D:\\迅雷云盘\\[公众号:分派电影]V字仇杀队.V.for.Vendetta.2005.BD1080P.中英双字.mp4");//用一个很大的文件, 比如电影来传.
            String readFile = preFile.getAbsolutePath();
            String writeFile = preFile.getParent() + File.separator + "单线程传输-" + start + ".mp4";//File.separator相当于路径分隔符
            byte[] bytes = new byte[2048];
            try (RandomAccessFile r = new RandomAccessFile(new File(readFile), "r");
                 RandomAccessFile w = new RandomAccessFile(new File(writeFile), "rw");) {
                int len = -1;
                while ((len = r.read(bytes)) != -1) {
                    w.write(bytes);
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("(end - start) = " + (end - start));
    
            /*传输测试时间结果(end - start) = 9520*/
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    RandomAccessFile实现大文件分片传输

        /**
         * @param :
         * @return void
         * @author Ladidol
         * @description 多线程分片对同一个文件进行读和写
         * @date 2022/6/29 21:14
         */
    
        @Test
        public void multiThreadReadAndWrite() throws ExecutionException, InterruptedException {
    
            //开始传输时间
            long start = System.currentTimeMillis();
    
            File preFile = new File("D:\\迅雷云盘\\[公众号:分派电影]V字仇杀队.V.for.Vendetta.2005.BD1080P.中英双字.mp4");
            String readFile = preFile.getAbsolutePath();//文件路径
            String writeFile = preFile.getParent() + File.separator + "多线程传输-" + start + ".mp4";//新文件名字
            long length = new File(readFile).length(); // 文件一共大小
            int slice = (int) length / 8; // 将文件分成8各部分来传.
            System.out.println("sliceNum = " + slice);
            List<long[]> longs = new ArrayList<>(8);
            for (int i = 0; i < 8; i++) {
                longs.add(new long[]{i * slice});
            }
    
            //开启线程.
            ExecutorService executorService = Executors.newCachedThreadPool();
            List<Future<?>> futures = new ArrayList<>();
            for (long[] aLong : longs) {
                long l = aLong[0]; // 起始位置
                // 创建线程并运行
                Future<?> randomAccessFile =
    //                    ExecutorUtils.createFuture(
                        executorService.submit(
                                () -> {
                                    byte[] bytes = new byte[slice];
                                    try (
                                            // 在线程内部创RandomAccessFile对象
                                            RandomAccessFile r = new RandomAccessFile(new File(readFile), "r");
                                            RandomAccessFile w = new RandomAccessFile(new File(writeFile), "rw");) {
    
                                        r.seek(l);
                                        int len = r.read(bytes);
                                        if (len < slice) {
                                            // 调整数组, 避免出现问题.
                                            bytes = getActualBytes(bytes,len);
                                        }
    
                                        // 写入文件
                                        w.seek(l);
                                        w.write(bytes);
                                        System.out.println("当前线程读写起点: " + l);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                    //callable的返回值
                                    return "call return " + Thread.currentThread().getName();
                                });
                futures.add(randomAccessFile);
            }
    
            int count = 0;
            for (Future<?> future : futures) {
                count++;
                if (!future.isDone()) {
                    System.out.println("资源还没有准备好" + count);
                }
                if (future.isDone()) {
                    System.out.println("资源准备好了捏!" + count);
                }
                System.out.println(future.get());
            }
    
            // 阻塞全部线程执行完毕
            executorService.shutdown();
            long end = System.currentTimeMillis();
            System.out.println("(end - start) = " + (end - start));
    
            /*传输测试时间结果(end - start) = 2377*/
    
        }
    
    
        /**
         * @param bytes:
         * @param len:
         * @return byte
         * @author Ladidol
         * @description 截取真实长度的数组.
         * @date 2022/6/30 14:07
         */
        byte[] getActualBytes(byte[] bytes, int len) {
            byte[] b1 = new byte[len];
            System.arraycopy(bytes, 0, b1, 0, len);
            return b1;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    文件夹情况:

    image-20220630145545196

    多线程使用RandomAccessFile

    常见的使用多线程的场景: 断点续传和断点下载,或者文件加密解密等

    断点续传原理就是:

    1. 前端将文件安装百分比进行计算,每次上传文件的百分之一(文件分片),给文件分片做上序号
    2. 后端将前端每次上传的文件,放入到缓存目录
    3. 等待前端将全部的文件内容都上传完毕后,发送一个合并请求
    4. 后端使用RandomAccessFile进多线程读取所有的分片文件,一个线程一个分片
    5. 后端每个线程按照序号将分片的文件写入到目标文件中,
    6. 在上传文件的过程中发生断网了或者手动暂停了,下次上传的时候发送续传请求,让后端删除最后一个分片
    7. 前端重新发送上次的文件分片

    END

    参考链接:

    Java-Io-RandomAccessFile(任意位置读写数据)_胡安民的博客-CSDN博客

  • 相关阅读:
    linux CentOS7.6安装jenkins(小白版本)
    02 stm32-hal库 timer 基本定时器设定
    尚医通 (十五) --------- 平台管理前端搭建
    到底什么是5G LAN?
    基于深度神经网络的社交媒体用户级心理压力检测
    MySQL:表的约束
    Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的
    C++ 继承多态的运用
    区块链与比特币学习笔记二
    每天学习一点点之 Spring Web MVC 之抽象 HandlerInterceptor 实现常用功能(限流、权限等)
  • 原文地址:https://blog.csdn.net/qq_51705526/article/details/125540719