Java swing 带界面和进度条的多线程下载器实现

前言

因为大作业要做浏览器,浏览器要带下载器,所以现在先实现一个带界面的多线程下载器类。

多线程下载器原理

之前写过一个的【Java URLConnection类 实现多线程下载文件】,只是那个demo比较简陋。。。

今天我们来加上图形界面,其实下载部分的代码都是复用过来的。。。。

JFrame

主窗体,windows窗口,可缩放等等

JTextField

文字框输入,我们需要用户输入或者改变

  1. 下载的url
  2. 保存地址
  3. 文件名

可以通过.set / get Text方法设置或者取得里面的文字

JButton

按钮组件,我们点击后,开始创建下载线程并且开始下载。

可以简单的为一个JButton对象绑定被点击时候的事件

// 开始下载按钮 注册事件 点击的时候创建新下载线程
JButton startBtn = new JButton("开始下载");
startBtn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // 按钮按下的时候执行此处代码
    }
});

JLabel

一个文字显示的组件,可以支持显示html格式,我们用于显示一些提示信息

JProgressBar

这次的重点,进度条组件,使用方便,在构造函数的时候,指定最小值,最大值

扫描二维码关注公众号,回复: 14318761 查看本文章
JProgressBar bar = new JProgressBar(0, 100);

然后可以通过.setValue来改变当前进度条的值

布局

JFrame使用【网格布局】,通过以下代码就可以实现一个9行1列的网格

// 主窗体
JFrame jf = new JFrame("下载器");
jf.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
jf.setSize(512, 321);
jf.setLayout(new GridLayout(9, 1));

实现

因为进度条需要调用组件,所以我们创建一个类叫MultiThreadDownloader,将所有组件都设置为成员变量

此外我们还要存一个下载进程,方便我们查看下载进度并且更新进度条,因为所有下载进程共享一个进度,我们保留其中一个下载进程,就可以轻松获取了。

public class MultiThreadDownloader {
    
    String url;             // 目标url
    String savePath;        // 本地保存路径
    String fileName;        // 文件名
    int tnum = 5;           // 默认线程数目
    long totalLength;       // 总大小
    DownloadThread dth;     // 一个下载线程,用于查看下载进度
    JLabel  urlInputText;   // 文字:目标对象url
    JTextField urlInput;    // url输入框
    JLabel  pathInputText;  // 文字:本地保存路径
    JTextField pathInput;   // 保存路径输入框
    JLabel  nameInputText;  // 文字:文件名
    JTextField nameInput;   // 文件名输入框
    JLabel  barTex;         // 文字:进度条
    JProgressBar bar;       // 进度条
    JButton startBtn;       // 开始下载按钮
    ExecutorService pool = Executors.newCachedThreadPool(); // 线程池
    
    MultiThreadDownloader() {
        
    }
    
    MultiThreadDownloader(String url, String savePath, String fileName, int tnum) {
        this.url = url;
        this.tnum = tnum;
        this.savePath = savePath;
        this.fileName = fileName;
    }
...
下面是类的其他方法实现
}

我们编写一个download方法,该方法初始化我们的界面并且显示,除此之外,还为按钮注册按下事件, 事件内容里面执行的代码就是创建下载线程并且开始下载。

public void download() throws Exception {
        
    // 初始化组件,利用默认内容
    // url输入
    urlInputText = new JLabel ("目标对象URL");
    urlInput = new JTextField(url);
    // 路径输入
    pathInputText = new JLabel ("本地保存路径");
    pathInput = new JTextField(savePath);
    // 文件名输入
    nameInputText = new JLabel ("文件名");
    nameInput = new JTextField(fileName);
    // 进度条
    JLabel  barText = new JLabel ("进度条");
    bar = new JProgressBar(0, 100);
    
    // 开始下载按钮 注册事件 点击的时候创建新下载线程
    startBtn = new JButton("开始下载");
    startBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            startBtn.setEnabled(false); // 按钮禁用
            // 获得用户实际输入的内容
            savePath = pathInput.getText();
            fileName = nameInput.getText();
            url = urlInput.getText();
            try {
                totalLength = new URL(url).openConnection().getContentLength();
                bar.setMaximum((int)totalLength);
                long eachLength = totalLength / tnum;
                // 拓展名
                String ext = url.substring(url.lastIndexOf("."));
                // 创建下载线程
                for(int i=0; i<tnum; i++) {     
                    long st = eachLength * i;
                    long ed = eachLength * (i+1);
                    if(i == tnum-1) {
                        ed=Math.max(ed, totalLength);
                    }
                    // 建立URL连接
                    URLConnection con = new URL(url).openConnection();
                    con.setRequestProperty("Range", "bytes="+String.valueOf(st)+"-"+String.valueOf(ed));
                    con.connect();
                    // 打开文件流
                    RandomAccessFile rf = new RandomAccessFile(savePath+fileName+ext, "rw");
                    rf.seek(st);    // 文件流跳转到对应位置
                    // 创建下载线程
                    DownloadThread d =new DownloadThread(con, rf);
                    pool.submit(d);
    
                    // 保存最后一个线程 方便查看进度
                    if(i==tnum-1) {
                        dth = d;
                    }
                }
                // 创建一个每500ms更新进度条的线程并且跑起来
                pool.submit(new Thread() {
                    public void run() {
                        while(true) {
                            bar.setValue((int)dth.allcur);
                            if(dth.allcur >= totalLength) {
                                startBtn.setText("下载完成");
                                break;
                            }
                            try {
                                this.sleep(500);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
                // 关闭线程池
                pool.shutdown();
            } catch(Exception e1) {
                e1.printStackTrace();
            }
        }
    });
    // 开始下载按钮 注册事件 -- 结束
    
    // 主窗体
    JFrame jf = new JFrame("下载器");
    jf.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    jf.setSize(512, 321);
    jf.setLayout(new GridLayout(9, 1));
    jf.add(urlInputText);
    jf.add(urlInput);
    jf.add(pathInputText);
    jf.add(pathInput);
    jf.add(nameInputText);
    jf.add(nameInput);
    jf.add(barText);
    jf.add(bar);
    jf.add(startBtn);
    jf.show();
}

main函数只需创建相应的下载器,调用download方法即可。

这里我在我的个人网址上提供了两个链接用于测试下载,分别是稍大的pdf文件和小型txt文件。

温馨提示
温馨提示

public static void main(String[] args) throws Exception {
    MultiThreadDownloader dl = new MultiThreadDownloader(
            "http://www.szulrl.cn/browserTest/PDFFILE.zip", 
            "E:/MyEclipse/WorkSpace/Hello/src/homework/", 
            "下载",
            3);
    dl.download();
}

完整代码

/*
 * @Author : @李若龙 2018171028 @SZU @CSSE
 */
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.html.*;

class DownloadThread extends Thread {
    
    URLConnection con;
    RandomAccessFile rf;
    
    public static volatile long allcur = 0;
    public static boolean isReady = false;
    
    public DownloadThread() {
        
    }
    
    public DownloadThread(URLConnection con, RandomAccessFile rf) {
        this.con = con;
        this.rf = rf;
    }
    
    public void run() {
        try {
            // 获取输入输出流
            InputStream is = con.getInputStream();
            //System.out.printf("线程 获取文件成功\n");
            
            // 输入流内容写入输出流
            byte[] buf = new byte[1024];
            int len = -1;
            
            while((len=is.read(buf)) != -1) {
                rf.write(buf, 0, len);
                synchronized(new Object()) {
                    allcur += (long)len;
                }
                // System.out.printf("%d / %d \n", allcur, 29210163);
            }
            rf.close();
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

public class MultiThreadDownloader {
    
    String url;             // 目标url
    String savePath;        // 本地保存路径
    String fileName;        // 文件名
    int tnum = 5;           // 默认线程数目
    long totalLength;       // 总大小
    DownloadThread dth;     // 一个下载线程,用于查看下载进度
    JLabel  urlInputText;   // 文字:目标对象url
    JTextField urlInput;    // url输入框
    JLabel  pathInputText;  // 文字:本地保存路径
    JTextField pathInput;   // 保存路径输入框
    JLabel  nameInputText;  // 文字:文件名
    JTextField nameInput;   // 文件名输入框
    JLabel  barTex;         // 文字:进度条
    JProgressBar bar;       // 进度条
    JButton startBtn;       // 开始下载按钮
    ExecutorService pool = Executors.newCachedThreadPool(); // 线程池
    
    MultiThreadDownloader() {
        
    }
    
    MultiThreadDownloader(String url, String savePath, String fileName, int tnum) {
        this.url = url;
        this.tnum = tnum;
        this.savePath = savePath;
        this.fileName = fileName;
    }
    
    public void download() throws Exception {
        
        // 初始化组件,利用默认内容
        // url输入
        urlInputText = new JLabel ("目标对象URL");
        urlInput = new JTextField(url);
        // 路径输入
        pathInputText = new JLabel ("本地保存路径");
        pathInput = new JTextField(savePath);
        // 文件名输入
        nameInputText = new JLabel ("文件名");
        nameInput = new JTextField(fileName);
        // 进度条
        JLabel  barText = new JLabel ("进度条");
        bar = new JProgressBar(0, 100);
        
        // 开始下载按钮 注册事件 点击的时候创建新下载线程
        startBtn = new JButton("开始下载");
        startBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                startBtn.setEnabled(false); // 按钮禁用
                // 获得用户实际输入的内容
                savePath = pathInput.getText();
                fileName = nameInput.getText();
                url = urlInput.getText();
                try {
                    totalLength = new URL(url).openConnection().getContentLength();
                    bar.setMaximum((int)totalLength);
                    long eachLength = totalLength / tnum;
                    // 拓展名
                    String ext = url.substring(url.lastIndexOf("."));
                    // 创建下载线程
                    for(int i=0; i<tnum; i++) {     
                        long st = eachLength * i;
                        long ed = eachLength * (i+1);
                        if(i == tnum-1) {
                            ed=Math.max(ed, totalLength);
                        }
                        // 建立URL连接
                        URLConnection con = new URL(url).openConnection();
                        con.setRequestProperty("Range", "bytes="+String.valueOf(st)+"-"+String.valueOf(ed));
                        con.connect();
                        // 打开文件流
                        RandomAccessFile rf = new RandomAccessFile(savePath+fileName+ext, "rw");
                        rf.seek(st);    // 文件流跳转到对应位置
                        // 创建下载线程
                        DownloadThread d =new DownloadThread(con, rf);
                        pool.submit(d);
                        if(i==tnum-1) {
                            dth = d;
                        }
                    }
                    // 创建一个每500ms更新进度条的线程
                    pool.submit(new Thread() {
                        public void run() {
                            while(true) {
                                //System.out.printf("%d / %d \n", dth.allcur, totalLength);
                                bar.setValue((int)dth.allcur);
                                if(dth.allcur >= totalLength) {
                                    startBtn.setText("下载完成");
                                    break;
                                }
                                try {
                                    this.sleep(500);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    });
                    // 关闭线程池
                    pool.shutdown();
                } catch(Exception e1) {
                    e1.printStackTrace();
                }
            }
        });
        // 开始下载按钮 注册事件 点击的时候创建新下载线程 -- 结束
        
        // 主窗体
        JFrame jf = new JFrame("下载器");
        jf.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        jf.setSize(512, 321);
        jf.setLayout(new GridLayout(9, 1));
        jf.add(urlInputText);
        jf.add(urlInput);
        jf.add(pathInputText);
        jf.add(pathInput);
        jf.add(nameInputText);
        jf.add(nameInput);
        jf.add(barText);
        jf.add(bar);
        jf.add(startBtn);
        jf.show();
        
    }
    
    public static void main(String[] args) throws Exception {
        MultiThreadDownloader dl = new MultiThreadDownloader(
                "http://www.szulrl.cn/browserTest/PDFFILE.zip", 
                "E:/MyEclipse/WorkSpace/Hello/src/homework/", 
                "下载",
                3);
        dl.download();
    }
}

猜你喜欢

转载自blog.csdn.net/m0_62051288/article/details/124214354