java多线程下载文件

java多线程下载文件

package com.study;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多线程下载文件
 * @Author: lhs
 * @Date: 2024/3/17 16:16
 */
public class FastDowload {
    private static String url = "https://www.xx.com/5236.mp4";
    static String fileName = "资料";// 保存文件名
    static String saveDir = "c:/temp/";// 保存目录
    private static int limit = 1024 * 1024; // 分段下载,每一段文件大小1M
    private static int N = 16;// 线程数16


    public static void main(String[] args) {
        downloadFile();
    }

    /**
     * 下载文件
     */
    public static void downloadFile() {
        try {
            // 文件总大小,单位:字节
            int size = getFileSize(url);
            // 分段下载,分几段
            int count = (size + limit - 1) / limit;
            AtomicInteger atomic = new AtomicInteger(0); // 分段下标
            AtomicInteger success = new AtomicInteger(0); // 下载成功个数
            // 下载线程池
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(N);
            for (int i = 0; i < count; i++) {
                fixedThreadPool.execute(() -> {
                    // 随机获取一个下标,获取其中一个文件
                    int index = atomic.getAndIncrement(); // 先返回,后自增
                    int start = index * limit;
                    int end = (index + 1) * limit - 1;
                    String range = start + "-" + end;
                    // 最后一段请求头
                    if (index == count - 1) {
                        range = start + "-";
                    }
                    // 失败后重试,最多重试50次
                    for (int j = 0; j < 50; j++) {
                        try {
                            byte[] bytes = sendGet(url, range);
                            if (bytes == null) {
                                System.out.println(count + "下载000" + (index + 1) + "失败:" + (j + 1) + "次," + range);
                                continue;
                            }
                            saveFile(bytes, "000" + (index + 1) + ".tmp");
                            System.out.println(count + "下载000" + (index + 1) + "成功:" + range);
                            success.getAndIncrement(); // 先返回,后自增
                            return;
                        } catch (Exception e) {
                            System.out.println(count + "下载000" + (index + 1) + "失败:" + (j + 1) + "次," + range);
                        }
                    }
                    System.out.println(count + "下载失败到达最大次数:下载000" + (index + 1) + "失败:" + range);
                });
            }
            fixedThreadPool.shutdown();
            // 等待子线程结束,再继续执行下面的代码
            fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
            System.out.println("所有文件下载结束,总共:" + count + "个文件!,成功:" + success.get() + "个文件!");

            // 合并文件
            mergeFile(count);
            System.out.println("合并完成,总共:" + count + "个文件!");

            // 删除文件
            deleteFile(count);
            System.out.println("成功,总共:" + count + "个文件!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存文件
     */
    private static void saveFile(byte[] bytes, String name) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(saveDir + name);
            fos.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除文件
     */
    private static void deleteFile(int count) {
        for (int i = 0; i < count; i++) {
            new File(saveDir + "000" + (i + 1) + ".tmp").delete();
        }
    }


    /**
     * 合并文件
     */
    private static void mergeFile(int count) {
        FileOutputStream fos = null;
        try {
            if ("".equals(fileName)) {
                fileName = "1" + new Random().nextInt(10000);
            }
            File file = new File(saveDir + fileName + ".mp4");
            fos = new FileOutputStream(file);
            int len;
            byte[] buf = new byte[4096];
            for (int i = 0; i < count; i++) {
                FileInputStream fis = new FileInputStream(saveDir + "000" + (i + 1) + ".tmp");
                while ((len = fis.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
                fos.flush();
                fis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 获取文件大小
     */
    private static int getFileSize(String url) {
        HttpsURLConnection connection = null;
        try {
            connection = (HttpsURLConnection) new URL(url).openConnection();
            // 绕过证书验证
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new MyTrustManager()}, new java.security.SecureRandom());
            connection.setSSLSocketFactory(sc.getSocketFactory());
            connection.setHostnameVerifier(new MyHostnameVerifier());
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            connection.connect();
            String contentLength = connection.getHeaderField("Content-Length");
            return Integer.parseInt(contentLength);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return 0;
    }

    /**
     * 下载其中一段文件
     */
    public static byte[] sendGet(String url, String range) {
        HttpsURLConnection connection = null;
        InputStream is = null;
        try {
            connection = (HttpsURLConnection) new URL(url).openConnection();
            // 绕过证书验证
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new MyTrustManager()}, new java.security.SecureRandom());
            connection.setSSLSocketFactory(sc.getSocketFactory());
            connection.setHostnameVerifier(new MyHostnameVerifier());
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(30000);
            // 下载其中一段文件
            connection.setRequestProperty("Range", "bytes=" + range);
            connection.connect();
            is = connection.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len;
            byte[] buf = new byte[1024];
            while ((len = is.read(buf)) != -1) {
                baos.write(buf, 0, len);
                baos.flush();
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    static class MyTrustManager implements X509TrustManager {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    static class MyHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String urlHostName, SSLSession session) {
            return true;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值