Java多线程下载

Java多线程下载

package com.orange;

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

public class Downloader {
    private URL url; // 目标地址
    private File file; // 本地文件
    private static final int THREAD_AMOUNT = 20; // 线程数
    private static final String DOWNLOAD_DIR_PATH = "/home/orange/桌面/"; // 下载目录
    private int threadLen; // 每个线程下载多少
    private volatile int downloadlen;
    private int totalLen;
    private volatile long sun;

    public Downloader(String address, String filename) throws IOException { // 通过构造函数传入下载地址
        url = new URL(address);
        File dir = new File(DOWNLOAD_DIR_PATH);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        file = new File(dir, filename);
    }

    public long download() throws IOException {
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);

        totalLen = conn.getContentLength(); // 获取文件长度
        threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT; // 计算每个线程要下载的长度

        System.out.println("totalLen=" + totalLen + ",threadLen:" + threadLen);

        RandomAccessFile raf = new RandomAccessFile(file, "rws"); // 在本地创建一个和服务端大小相同的文件
        raf.setLength(totalLen); // 设置文件的大小
        raf.close();

        for (int i = 0; i < THREAD_AMOUNT; i++) // 开启3条线程, 每个线程下载一部分数据到本地文件中
            new DownloadThread(i).start();

        return this.sun;
    }

    private class DownloadThread extends Thread {
        private int id;

        public DownloadThread(int id) {
            this.id = id;
        }

        public void run() {
            long startdate = System.currentTimeMillis();
            int start = id * threadLen; // 起始位置
            int end = id * threadLen + threadLen - 1; // 结束位置
            System.out.println("线程" + id + "下载的范围:\t" + start + "-" + end);

            try {
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestProperty("Range", "bytes=" + start + "-" + end); // 设置当前线程下载的范围

                InputStream in = conn.getInputStream();
                RandomAccessFile raf = new RandomAccessFile(file, "rws");
                raf.seek(start); // 设置保存数据的位置

                byte[] buffer = new byte[102400];
                int len = 0;
                while ((len = in.read(buffer)) != -1) {
                    raf.write(buffer, 0, len);
                    downloadlen = downloadlen + len;
                    System.out.println("当前下载进度\t" + downloadlen + "/" + totalLen+"\t\t\t" + (downloadlen/totalLen)*100 + "%\r" );
                }
                raf.close();
                long enddate = System.currentTimeMillis();
                sun = sun + (enddate - startdate);
                System.out.println("线程" + id + "下载完毕,耗时" + (enddate - startdate) + "毫秒");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        String add = "http://hub.meefik.ru/rootfs/alpine_arm64.tgz";
        long sun = new Downloader(add, "alpine_arm64.tgz").download();
        System.out.println(sun);
        
    }
}