ui界面:

package DownLoaderItem;import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.util.List;public class DownLoaderUI extends JFrame implements ActionListener{private JLabel lburl;private TextField tfurl;private DownLoader downLoader;private JLabel lblocation;private TextField tfloacation;private JLabel lbcount;private TextField tfcount;private int completed=0;private JButton btnstar;public JButton btnpause;public JProgressBar[] bars;public DownLoaderUI(){ init(); this.setVisible(true);}private void init() { this.setBounds(100,50,800,600); this.setLayout(null); lburl=new JLabel("url地址"); lburl.setBounds(0,0,100,30); this.add(lburl); tfurl=new TextField("http://localhost:8092/2018-07-01.log"); tfurl.setBounds(0,40,800,30); this.add(tfurl); lblocation=new JLabel("保存地址"); lblocation.setBounds(0,80,100,30); this.add(lblocation); tfloacation=new TextField("d:/test/down/2018-07-01.log"); tfloacation.setBounds(0,120,800,30); this.add(tfloacation); lbcount=new JLabel("线程数"); lbcount.setBounds(0,160,100,30); this.add(lbcount); tfcount=new TextField("3"); tfcount.setBounds(0,200,800,30); this.add(tfcount); btnstar=new JButton("开始"); btnstar.setBounds(0,240,100,30); btnstar.addActionListener(this); this.add(btnstar); btnpause=new JButton("暂停"); btnpause.setBounds(150,240,100,30); btnpause.addActionListener(this); this.add(btnpause); this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(-1); } });}@Overridepublic void actionPerformed(ActionEvent e) { Object source = e.getSource(); //如果点击事件为开始 if(source==btnstar){ String url = tfurl.getText(); String location = tfloacation.getText(); int count=Integer.parseInt(tfcount.getText()); downLoader = new DownLoader(url, location, count, this); addBars(downLoader.getDownLoaderInfos()); downLoader.startDownload(); //如果点击事件为暂停 }else if(source==btnpause){ //通过调节下载线程中的静态标记,来调节按钮的名字与开始暂停 DownLoaderThread.pause=!DownLoaderThread.pause; if(DownLoaderThread.pause){ btnpause.setText("继续"); }else{ btnpause.setText("暂停"); } }}private void addBars(List<DownLoaderInfo> list) { //添加进度条数组 bars=new JProgressBar[list.size()]; //循环所有的线程,创建进度条 for (DownLoaderInfo di : list) { bars[di.getIndex()]=new JProgressBar(); bars[di.getIndex()].setBounds(10,280+(di.getIndex()*50),750,30); //设置最大值 bars[di.getIndex()].setMaximum(di.getEndPos()-di.getStartPose()+1); //取出上次进度条所走的进度值 bars[di.getIndex()].setValue(di.getAmount()); this.add(bars[di.getIndex()]); } this.repaint();}public void updataBars(int index, int len) { //更新进度条 bars[index].setValue(bars[index].getValue()+len); synchronized (this){ //如果一个进度条的值大于等于它的最大值了,就是下完了 if(bars[index].getValue()>=bars[index].getMaximum()){ completed++; //如果进度条的数量等于已下载的数量说明全下完了,就可以删除进度条了 if(bars.length==completed){ for (JProgressBar bar : bars) { this.remove(bar); } this.repaint(); completed=0; bars=null; downLoader.prop=null; //下完之后需要关闭进程 BackWriteThread.stop=true; //下载完成后删除文件 downLoader.deleteMetaFile(); } } }}}

主入口:

package DownLoaderItem;public class Mainx { public static void main(String[] args) { new DownLoaderUI(); }}

下载器类:

package DownLoaderItem;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLConnection;import java.util.ArrayList;import java.util.List;import java.util.Properties;public class DownLoader { private String url; private String location; private int count; //传递prop,把下载进度写入到prop中 public Properties prop; //把下载信息组成集合 public List<DownLoaderInfo> getDownLoaderInfos() { return downLoaderInfos; } public void setDownLoaderInfos(List<DownLoaderInfo> downLoaderInfos) { this.downLoaderInfos = downLoaderInfos; } private DownLoaderUI ui; public List<DownLoaderInfo> downLoaderInfos; public DownLoader(String url, String location, int count, DownLoaderUI ui) { this.url = url; this.location = location; this.count = count; this.ui = ui; initDownloaderInfos(); } public void startDownload(){ for (DownLoaderInfo di : downLoaderInfos) { new DownLoaderThread(di,ui,this.prop).start(); } //起新线程写入后台 new BackWriteThread(location,prop).start(); } private void initDownloaderInfos() { downLoaderInfos=new ArrayList<>(); //如果是第一次下载 if(!isFirst()){ int blockSize=getLen()/count; for (int i=0;i<count;i++){ int startPos=i*blockSize; int endPos=0; if(i==count-1){ endPos=getLen()-1; }else { endPos=(i+1)*blockSize-1; } DownLoaderInfo d = new DownLoaderInfo(url, location, startPos, endPos, i, 0); //把下载信息添加进集合 downLoaderInfos.add(d); } //首次下载后把元数据创建出来,并写入到文件 creatMetaDate(downLoaderInfos); //如果不是首次下载 }else { try { File f = new File(location + ".meta"); prop = new Properties(); FileInputStream fis = new FileInputStream(f); prop.load(fis); //取出线程数 int count = Integer.parseInt(prop.getProperty("thread.count")); for (int i=0;i<count;i++){ //循环所有线程,取出重要数据 int startPos = Integer.parseInt(prop.getProperty("thread."+i+".startPos")); int endPos = Integer.parseInt(prop.getProperty("thread."+i+".endPos")); int amount = Integer.parseInt(prop.getProperty("thread."+i+".amount")); DownLoaderInfo d = new DownLoaderInfo(url, location, startPos, endPos, i, amount); downLoaderInfos.add(d); } }catch (Exception e){ e.printStackTrace(); } } } private void creatMetaDate(List<DownLoaderInfo> list) { try { File f = new File(location + ".meta"); prop = new Properties(); prop.setProperty("thread.count",list.size()+""); //循环线程,把重要数据写入到元数据文件 for (DownLoaderInfo di : list) { prop.setProperty("thread."+di.getIndex()+".startPos",di.getStartPose()+""); prop.setProperty("thread."+di.getIndex()+".endPos",di.getEndPos()+""); prop.setProperty("thread."+di.getIndex()+".amount",di.getAmount()+""); } FileOutputStream fos = new FileOutputStream(f); prop.store(fos,"xxx"); fos.close(); }catch (Exception e){ e.printStackTrace(); } } public boolean isFirst(){ return new File(location).exists(); } //获得url,与下载文件的长度 public int getLen(){ try { URL u = new URL(this.url); HttpURLConnection conn= (HttpURLConnection) u.openConnection(); int len = conn.getContentLength(); conn.disconnect(); return len; }catch (Exception e){ e.printStackTrace(); } return -1; } //删除元数据文件 public void deleteMetaFile(){ File f = new File(location + ".meta"); while (!f.delete()){ } }}

下载线程类:

package DownLoaderItem;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.util.Properties;public class DownLoaderThread extends Thread { private DownLoaderInfo info; private DownLoaderUI ui; public static boolean pause=false; private Properties prop; public DownLoaderThread(DownLoaderInfo info, DownLoaderUI ui,Properties prop) { this.info = info; this.ui = ui; this.prop=prop; } @Override public void run() { try { URL u = new URL(info.getUrl()); HttpURLConnection conn= (HttpURLConnection) u.openConnection(); //设置下载偏移量 conn.setRequestProperty("Range","bytes="+(info.getStartPose()+info.getAmount())+"-"+info.getEndPos()); InputStream in = conn.getInputStream(); RandomAccessFile raf = new RandomAccessFile(info.getLocation(), "rw"); //取得下载偏移量 raf.seek(info.getStartPose()+info.getEndPos()); byte[] buf=new byte[1024]; int len=0; while((len=in.read(buf))!=-1){ //如果标记为为true就暂停 while(pause){ Thread.sleep(1000); } raf.write(buf,0,len); //更新下载进度到prop线程 updataAmount(info.getIndex(),len); //更新进度条 ui.updataBars(info.getIndex(),len); Thread.sleep(1); } raf.close(); in.close(); conn.disconnect(); }catch (Exception e){ e.printStackTrace(); } } //更新amount到prop private void updataAmount(int index, int len) { int amount = Integer.parseInt(prop.getProperty("thread."+index+".amount")); prop.setProperty("thread."+index+".amount",(amount+len)+""); }}

封装下载信息类:

package DownLoaderItem;public class DownLoaderInfo { private String url; private String location; private int startPose; private int endPos; private int index; public DownLoaderInfo(String url, String location, int startPose, int endPos,int index) { this.url = url; this.location = location; this.startPose = startPose; this.endPos = endPos; this.index=index; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public int getStartPose() { return startPose; } public void setStartPose(int startPose) { this.startPose = startPose; } public int getEndPos() { return endPos; } public void setEndPos(int endPos) { this.endPos = endPos; }}

后台分线程写入文件类:

package DownLoaderItem;import java.io.File;import java.io.FileOutputStream;import java.util.Properties;public class BackWriteThread extends Thread { private String location; private Properties prop; public static boolean stop=false; public BackWriteThread(String location, Properties prop) { this.location = location; this.prop = prop; this.setDaemon(true); } @Override public void run() { //把最新的进度通过分线程写到文件中 File f = new File(location + ".meta"); try { while(f.exists() && prop!=null) { if(stop){ return; } FileOutputStream fos = new FileOutputStream(f); prop.store(fos, "xxx"); fos.close(); Thread.sleep(1000); } }catch (Exception e){ e.printStackTrace(); } }}