java多线程下载_java多线程下载

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

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

//循环所有线程,取出重要数据

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 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();

}

}

}

1.得到服务器下载文件的大小,然后在本地设置一个临时文件和服务器端文件大小一致 a)获得访问网络地址 b)通过URL对象的openConnection()方法打开连接,返回一个连接对象 c)设置请求头 i.setRequestMethod ii.setConnectTimeout iii.setReadTimeout d)判断是否响应成功 e)获取文件长度(getContentLength()) f)随机访问文件的读取与写入RandomAccessFile(file, mode) g)设置临时文件与服务器文件大小一致(setLength()) h)关闭临时文件 2.计算出每个线程下载的大小(开始位置,结束位置) a)计算出每个线程下载的大小 b)for循环,计算出每个线程的开始、结束位置 c)最后一个线程处理 3.每创建好一次就要开启线程下载 a)构造方法 b)通过URL对象的openConnection()方法打开连接,返回一个连接对象 c)设置请求头 i.setRequestMethod ii.setConnectTimeout d)判断是否响应成功(206) e)获取每个线程返回的流对象 f)随机访问文件的读取与写入RandomAccessFile(file, mode) g)指定开始位置 h)循环读取 i.保存每个线程下载位置 ii.记录每次下载位置 iii.关闭临时记录位置文件 iv.随机本地文件写入 v.记录已下载大小 i)关闭临时文件 j)关闭输入流 4.为了杀死线程还能继续下载的情况下,从本地文件上读取已经下载文件的开始位置 a)创建保存记录结束位置的文件 b)读取文件 c)将流转换为字符 d)获取记录位置 e)把记录位置赋给开始位置 5.当你的n个线程都下载完毕的时候我进行删除记录下载位置的缓存文件 a)线程下载完就减去 b)当没有正在运行的线程时切文件存在时删除文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值