分享一个多线程分片下载url资源的代码

最近一直在做视频这块的一个拓展应用,其中涉及到视频下载、视频静止内容分析、视频语音识别文字等方面的应用,其中最关键的是要从存储服务器获取当前需要操作的视频,所以就写了个视频下载的一个小模块,现分享给大家,希望能帮到一些有类似需求的童鞋们,有其它的一些需求的,也可以在我的代码的基础上去修改,也欢迎大家给我指出不足,共同进步,代码如下:

首先要获取 HttpURLConnection 连接,创建一个HttpConnectionUtil.java这个类:

package com.wal.utils.downloadutils;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 获取 HttpURLConnection 连接
 * @author wal
 * @date 2019/5/22
 */
public class HttpConnectionUtil {

    // 记录读取了多少,一共读取了多少
    private  long start;

    // 记录文件总大小
    private  long sum;

    public long getStart() {
        return start;
    }

    public void setStart(long start) {
        this.start = start;
    }

    public long getSum() {
        return sum;
    }

    public void setSum(long sum) {
        this.sum = sum;
    }


    /**
     *
     * @Title: getHttpConnection
     * @Description: 获取 url 连接
     * @param: @param urlLocation
     * @param: @return HttpURLConnection实例化对象
     * @param: @throws IOException
     * @return: HttpURLConnection
     * @throws
     */
    public static HttpURLConnection getHttpConnection(String urlLocation) throws IOException {
        URL url = new URL(urlLocation);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");

        return conn;
    }


}

然后创建一个文件下载类DownloadFileRang.java,集成Runnable 实现多线程:

package com.wal.utils.downloadutils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;

/**
 * 文件下载类,此处使用 继承 Runnable 实现多线程
 * @author wal
 * @date 2019/5/22
 */
public class DownloadFileRang implements Runnable {
    // 文件开始位置
    private long start ;
    // 文件结束位置
    private long end;
    // url地址
    private String urlLocation;
    // 文件存储位置
    private String filePath;

    private HttpConnectionUtil httpConnectionUtil;

    public HttpConnectionUtil getHttpConnectionUtil() {
        return httpConnectionUtil;
    }

    public void setHttpConnectionUtil(HttpConnectionUtil httpConnectionUtil) {
        this.httpConnectionUtil = httpConnectionUtil;
    }

    public DownloadFileRang(long start, long end, String urlLocation, String filePath, HttpConnectionUtil httpConnectionUtil) {
        super();
        this.start = start;
        this.end = end;
        this.urlLocation = urlLocation;
        this.filePath = filePath;
        this.httpConnectionUtil = httpConnectionUtil;
    }

    @Override
    public void run() {
        HttpURLConnection conn = null;
        InputStream is = null;
        RandomAccessFile out = null;
        try {
            // 获取连接
            conn = httpConnectionUtil.getHttpConnection(urlLocation);
            // 设置获取资源范围
            conn.setRequestProperty("Range", "bytes=" + start +"-"+end );

            File file = new File(filePath);

            if(file!=null) {
                out = new RandomAccessFile(file, "rw");
            }
            out.seek(start);

            // 获取网络连接的 输入流
            is = conn.getInputStream();

            byte [] data = new byte[1024];
            int len = 0;
            while( (len = is.read(data))!=-1 ) {
                out.write(data, 0, len);
                synchronized (HttpConnectionUtil.class) {
                    httpConnectionUtil.setStart(httpConnectionUtil.getStart()+len);
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 关闭连接
            try {
                out.close();
                is.close();
                conn.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
文件切片,分别指定 起始点,创建DownloadFilePool.java
package com.wal.utils.downloadutils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 文件切片,分别指定 起始点,注意这里的起始点是包头也包尾的,0-10/11-20/21-30  这种
 * @author wal
 * @date 2019/5/22
 */
public class DownloadFilePool {

    // 网络资源路径
    private String urlLocation;
    // 存储路径
    private String filePath;
    // 多少个线程
    private int poolLength;

    private DownloadFileRang downloadFileRang;

    public DownloadFilePool(String urlLocation, String filePath, int poolLength) {
        super();
        // 如果 保存路径为空则默认存在 D盘,文件名跟下载名相同
        if( filePath==null ) {
            String fileName = urlLocation.substring( urlLocation.lastIndexOf("/") +1);
            filePath = "D:/ZZZ/" + fileName;
        }
        this.urlLocation = urlLocation;
        this.filePath = filePath;
        this.poolLength = poolLength;
    }

    public DownloadFileRang getDownloadFileRang() {
        return downloadFileRang;
    }

    public void setDownloadFileRang(DownloadFileRang downloadFileRang) {
        this.downloadFileRang = downloadFileRang;
    }

    public void getFile() {
        HttpConnectionUtil httpConnectionUtil = new HttpConnectionUtil();
        try {
            // 获取文件长度
            long fileLength = httpConnectionUtil.getHttpConnection(urlLocation).getContentLengthLong();
            httpConnectionUtil.setSum(fileLength) ;

            ExecutorService pool = Executors.newCachedThreadPool();

            // 获取每片大小
            long slice = fileLength/poolLength;
            for(int i = 0 ;i < poolLength; i++) {
                long start = i*slice;
                long end = (i+1)*slice -1;

                if(i==poolLength-1) {
                    start = i*slice;
                    end =  fileLength ;
                }
                System.out.println(  start + "---" + end  );
                // 创建下载类
                downloadFileRang = new DownloadFileRang(start, end, urlLocation, filePath, httpConnectionUtil);
                // 执行线程
                pool.execute(downloadFileRang);
            }
            // 关闭线程池
            pool.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

最后在service层调用此工具类:


    public void download(Integer filecode, String url, String filename){


        //判断文件夹是否存在,不存在创建
        File targetFile = new File(BasePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }

        ExecutorService executor = Executors.newCachedThreadPool();

        executor.execute(() -> {
            /** 下载到本地   开始**/
            long begin_time = new Date().getTime();
            String videoRealPath = null;
            long time = 0;
            try {
                videoRealPath = BasePath+filename;

                File newTargetFile = new File(videoRealPath);//判断是否存在,存在删除后继续下载
                if (newTargetFile.exists()) {
                    newTargetFile.delete();
                }

                DownloadFilePool pool = new DownloadFilePool(url, videoRealPath, 100);
                pool.getFile();

                long old = 0;
                long now = 0;
                while (pool.getDownloadFileRang().getHttpConnectionUtil().getSum() >= pool.getDownloadFileRang().getHttpConnectionUtil().getStart()) {
                    now = pool.getDownloadFileRang().getHttpConnectionUtil().getStart() - old;
                    old = pool.getDownloadFileRang().getHttpConnectionUtil().getStart();

                    if (pool.getDownloadFileRang().getHttpConnectionUtil().getSum() == pool.getDownloadFileRang().getHttpConnectionUtil().getStart()) {

                        long t = new Date().getTime() - begin_time;
                        long seconds = t / 1000;
                        long minutes = seconds / 60;
                        long second = seconds % 60;

                        double speed = ((double) pool.getDownloadFileRang().getHttpConnectionUtil().getSum() / (t / 1000.0)) / 1024.0 / 1024.0;

                        log.info("下载完成,用时:{}分{}秒,平均网速:{}M/s",minutes,second,speed);
                        break;
                    }

                    System.out.println("网速:" + ((double) (now / 0.5)) / 1024.0 / 1024.0 + " M/s,已完成:" + (pool.getDownloadFileRang().getHttpConnectionUtil().getStart() / (double) pool.getDownloadFileRang().getHttpConnectionUtil().getSum()) * 100 + "%");

                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                /** 下载到本地   结束**/


            } catch (Exception e) {
                System.out.println("文件:"+filename+",下载失败");
                log.error(e.getMessage());
            }
        });

        executor.shutdown();

    }

有不懂的地方可以给我留言,或者进群交流!

你可能感兴趣的:(工具,插件,java)