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);
}
});
}
@Override
public 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 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 getDownLoaderInfos() {
return downLoaderInfos;
}
public void setDownLoaderInfos(List downLoaderInfos) {
this.downLoaderInfos = downLoaderInfos;
}
private DownLoaderUI ui;
public List 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 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();
}
}
}