前言
因为大作业要做浏览器,浏览器要带下载器,所以现在先实现一个带界面的多线程下载器类。
多线程下载器原理
之前写过一个的【Java URLConnection类 实现多线程下载文件】,只是那个demo比较简陋。。。
今天我们来加上图形界面,其实下载部分的代码都是复用过来的。。。。
JFrame
主窗体,windows窗口,可缩放等等
JTextField
文字框输入,我们需要用户输入或者改变
- 下载的url
- 保存地址
- 文件名
可以通过.set / get Text方法设置或者取得里面的文字
JButton
按钮组件,我们点击后,开始创建下载线程并且开始下载。
可以简单的为一个JButton对象绑定被点击时候的事件
// 开始下载按钮 注册事件 点击的时候创建新下载线程JButton startBtn = new JButton("开始下载");startBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 按钮按下的时候执行此处代码 }});
JLabel
一个文字显示的组件,可以支持显示html格式,我们用于显示一些提示信息
JProgressBar
这次的重点,进度条组件,使用方便,在构造函数的时候,指定最小值,最大值
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文件。
http://www.szulrl.cn/browserTest/PDFFILE.zip
http://www.szulrl.cn/browserTest/TXTFILE.zip
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(); }}
来源:
https://mp.weixin.qq.com/s/DTnch_ibXswXOXNvZyWb4A