zoukankan      html  css  js  c++  java
  • 多线程下载工具

    本文出自:《疯狂java讲义第3版本》第十七章

    下载url文件,并不是线程越多,下载的越快,一定是有一个最佳的方案。
    测试经过:path为20M的MP3文件 , 用1个线程用时:13197ms;用2个线程用时8560ms;用3个线程用时:13894ms;用4个线程用时16648ms;
    具体还是要根据项目环境做选择。

    import java.io.BufferedInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Date;
    
    /**
     * 多线程下载工具
     */
    public class DownUtil {
        private String path;            //下载文件的路径
        private String targetFile;      //文件保存的位置
        private int threadNum;          //下载资源的线程数
        private DownThread[] threads;   //线程数组
        private int fileSize;           //文件的字节数
    
        public DownUtil(String path, String targetFile, int threadNum) {
            this.path = path;
            this.targetFile = targetFile;
            this.threadNum = threadNum;
            threads = new DownThread[threadNum];
        }
    
        public void download() throws IOException {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5 * 1000);
            conn.setRequestMethod("GET");
            fileSize = conn.getContentLength();
            conn.disconnect();
            int currentPartSize = fileSize / threadNum + 1;
            RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
            file.setLength(fileSize);   //设置文件大小
            file.close();
            for (int i = 0; i < threadNum; i++) {
                //计算每个线程开始下载的位置
                int startPos = i * currentPartSize;
                //每一个线程使用一个RandomAccessFile下载
                RandomAccessFile currentPart = new RandomAccessFile(targetFile, "rw");
                //定位该线程的下载位置
                currentPart.seek(startPos);
                //创建下载线程
                threads[i] = new DownThread(startPos, currentPartSize, currentPart);
                //启动下载线程
                threads[i].start();
            }
        }
    
        /**
         * 获取下载百分比
         */
        public double getCompleteRate() {
            int sumSize = 0;
            for (int i = 0; i < threadNum; i++) {
                sumSize += threads[i].length;
            }
            return sumSize * 1.0 / fileSize;
        }
    
        private class DownThread extends Thread {
    
            private int startPos;                   //当前线程的下载位置
            private int currentPartSize;            //当前线程需要负责的大小
            private RandomAccessFile currentPart;   //当前线程需要下载的文件块
            private int length;                     //该文件已下载的字节数
    
    
            public DownThread(int startPos, int currentPartSize, RandomAccessFile currentPart) {
                this.startPos = startPos;
                this.currentPartSize = currentPartSize;
                this.currentPart = currentPart;
            }
    
            public void run() {
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(5 * 1000);
                    conn.setRequestMethod("GET");
                    InputStream in = conn.getInputStream();
                    BufferedInputStream bis = new BufferedInputStream(in);
                    bis.skip(startPos);
                    byte[] buff = new byte[1024];
                    int hasRead = 0;
                    while (length < currentPartSize && (hasRead = bis.read(buff)) != -1) {
                        currentPart.write(buff, 0, hasRead);
                        length += hasRead;
                    }
                    currentPart.close();
                    bis.close();
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) throws IOException {
            DownUtil downUtil = new DownUtil("http://www.ytmp3.cn/down/57196.mp3", "G:/57196.mp3", 2);
            long start = new Date().getTime();
            downUtil.download();
    
            new Thread(() -> {
                while (downUtil.getCompleteRate() < 1) {
                    long end = new Date().getTime();
                    System.out.println("已完成:"+(end -start) +"ms"+ downUtil.getCompleteRate());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    温故而知新
  • 相关阅读:
    mysql索引数据结构
    29. 使用参数化编写自动化测试用例
    28. Python编写自动化测试用例
    27. Unittest单元测试框架的介绍与使用
    26. 什么是单元测试
    25. Postman的使用
    24. 接口测试的意义
    23. requests安装与使用
    22. 如何编写接口文档
    21. Blog接口开发
  • 原文地址:https://www.cnblogs.com/Uzai/p/10295855.html
Copyright © 2011-2022 走看看