• Java之多线程断点下载的实现


    RandomAccessFile类:
    此类的实例支持对随机訪问文件的读取和写入。随机訪问文件的行为相似存储在文件系统中的一个大型 byte 数组。

    存在指向该隐含数组。光标或索引,称为文件指针。输入操作从文件指针開始读取字节。并随着对字节的读取而前移此文件指针。

    假设随机訪问文件以读取/写入模式创建,则输出操作也可用。输出操作从文件指针開始写入字节。并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针能够通过 getFilePointer 方法读取。并通过 seek 方法设置。

    以下有RandomAccessFile实现安卓下的断点下载的demo。


    server端能够用tomcat模拟。将被下载的測试文件放入webApp/ROOT文件夹下就可以。
    先给出java借助HttpURLConnection类实现的多线程下载代码:

    public class MultiThread {
        private static int threadCount = 3;
        private static long blockSize;
        private static int runningThreadCount;
        public static void main(String[] args) throws Exception {
            String path = "http://10.0.67.172/test.exe";
            URL url = new URL(path); 
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);//超时时间
            int code = conn.getResponseCode();
            System.out.println(code);
    
            if(code / 100 == 2){
                int size = conn.getContentLength();//获取资源文件的长度
                System.out.println("请求资源大小:" + size);
                blockSize = size / threadCount;//将资源文件分为多少块。没一块的大小
    
                runningThreadCount = threadCount;
                long startIndex = 0;
                long endIndex = 0;
                //开启若干个子线程去实现多线程的下载
                for(int i = 0; i < threadCount; i++){
                    startIndex = i * blockSize;
                    endIndex = (i + 1) * blockSize - 1;
                    if(i == threadCount-1){
                        endIndex = size - 1;
                    }
                    System.out.println("开启线程:" + i + ";" + "開始位置:" + startIndex + ":" + "结束位置:" + endIndex);
                    new DownThread(path, startIndex, endIndex, i).start();
                }
            }
        }
    
        private static class DownThread extends Thread{
            private String path;
            private long startIndex;
            private long endIndex;
            private int threadId;
    
            public DownThread(String path, long startIndex, long endIndex, int threadId) {
                super();
                this.path = path;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
                this.threadId = threadId;
            }
    
            @Override
            public void run() {
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setReadTimeout(5000);
                    conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);//设置server上的文件的读取位置
    
                    int code = conn.getResponseCode();
                    if(code / 100 == 2){
                        InputStream is = conn.getInputStream();
                        File file = new File("temp.exe");
                        RandomAccessFile raf = new RandomAccessFile(file, "rw");
                        raf.seek(startIndex);
                        System.out.println("第" + threadId + "个文件的開始位置:" + String.valueOf(startIndex));
                        int len = 0;
                        byte[] buffer = new byte[1024];
                        while ((len = is.read(buffer)) != -1){
                            raf.write(buffer, 0, len);//写文件
                        }
                        raf.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    断点下载的原理就是将上次文件下载的位置保存为暂时文件,当全然完成下载时再删除。

    public class MultiThread {
        private static int threadCount = 3;
        private static long blockSize;
        private static int runningThreadCount;
        public static void main(String[] args) throws Exception {
            String path = "http://10.0.67.172/test.rar";
            URL url = new URL(path); 
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);//超时时间
            int code = conn.getResponseCode();
            System.out.println(code);
    
            if(code / 100 == 2){
                int size = conn.getContentLength();//获取资源文件的长度
                System.out.println("请求资源大小:" + size);
                blockSize = size / threadCount;//将资源文件分为多少块,没一块的大小
    
                runningThreadCount = threadCount;
                long startIndex = 0;
                long endIndex = 0;
                for(int i = 0; i < threadCount; i++){
                    startIndex = i * blockSize;
                    endIndex = (i + 1) * blockSize - 1;
                    if(i == threadCount-1){
                        endIndex = size - 1;
                    }
                    System.out.println("开启线程:" + i + ";" + "開始位置:" + startIndex + ":" + "结束位置:" + endIndex);
                    new DownThread(path, startIndex, endIndex, i).start();
                }
            }
        }
    
        private static class DownThread extends Thread{
            private String path;
            private long startIndex;
            private long endIndex;
            private int threadId;
    
            public DownThread(String path, long startIndex, long endIndex, int threadId) {
                super();
                this.path = path;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
                this.threadId = threadId;
            }
    
            @Override
            public void run() {
                int total = 0;
                try {
                    File positionFile = new File(threadId + ".txt");
    
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    //接着上次的文件继续下载
                    if(positionFile.exists() && positionFile.length() > 0){
                        FileInputStream fis = new FileInputStream(positionFile);
                        BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
                        //获取当前线程上次下载的总大小是多少
                        String lasttotalstr = reader.readLine();
                        int lastTotal = Integer.valueOf(lasttotalstr);
                        System.out.println("上次线程下载的总大小:" + lastTotal);
                        startIndex += lastTotal;
                        total += lastTotal;
                        fis.close();
                    }
                    conn.setReadTimeout(5000);
                    conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);//设置server上的文件的读取位置
    
                    int code = conn.getResponseCode();
                    if(code / 100 == 2){
                        InputStream is = conn.getInputStream();
                        File file = new File("temp.rar");
                        RandomAccessFile raf = new RandomAccessFile(file, "rw");
                        raf.seek(startIndex);
                        System.out.println("第" + threadId + "个文件的開始位置:" + String.valueOf(startIndex));
                        int len = 0;
                        byte[] buffer = new byte[1024];
                        while ((len = is.read(buffer)) != -1){
                            RandomAccessFile rf = new RandomAccessFile(positionFile, "rwd");
                            raf.write(buffer, 0, len);//写文件
                            total += len;
                            rf.write(String.valueOf(total).getBytes());
                            rf.close();
                        }
                        is.close();
                        raf.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    synchronized (DownThread.class) {
                        System.out.println("线程" + threadId + "完成下载了");
                        runningThreadCount--;
                        if (runningThreadCount < 1) {
                            System.out.println("全部的线程都工作完成了。删除暂时记录的文件");
                            for (int i = 0; i < threadCount; i++) {
                                File f = new File(i + ".txt");
                                System.out.println(f.delete());
                            }
                        }
                    }
                }
            }
        }
    }

    执行结果截图:这里写图片描写叙述

  • 相关阅读:
    一套简单通用的Java后台管理系统(SpringBoot +Security + Layui实现一套权限管理后台模板)
    org.thymeleaf.exceptions.TemplateInputException: Error resolving template [cart/getCurrentUserCartItem], template might not exist or might not be accessible by any of the configured Template Resolvers
    ARTS-WEEK-009
    ARTS-WEEK-008
    从一次外卖到对oauth2.0的思考
    网络滴神,TCP!
    浪里来浪里去!网络协议如何成就网上冲浪?
    IO、NIO实现简单聊天室,附带问题解析
    IntelliJ IDEA 中使用 Lambok (注解无效问题的解决)
    M5310-A 版本
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5303691.html
Copyright © 2020-2023  润新知