一个简单的下载工具源代码(Java语言编写)
[code]package crazysheep;import java.awt.BorderLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
//定义类Main类并实现Observer方法
public class Main extends JFrame implements Observer {
// 创建了一个文本框t1
private JTextField t1;
private JTextField t2;
private Label L1;
private Label L2;
// 用类Table定义了一个tableModel
private Table tableModel;
// 创建了一个表
private JTable table;
// 创建了四个按钮
private JButton pauseButton, resumeButton;
private JButton cancelButton, clearButton;
// 用类Download定义了一个selectedDownload
private Download selectedDownload;
// 定义了一个boolean形的clearing
private boolean clearing;
public Main() {
// 初始化UI标题
setTitle("■ Crazy Sheep ■多线程下载工具");
// 初始化UI大小
setSize(500, 250);
setLocation(256, 280);
setResizable(false);
// 定义一个容器
JPanel addPanel = new JPanel();
// 添加一个长度为30的文本框
t1 = new JTextField(15);
t2 = new JTextField(15);
L1 = new Label("远程地址:");
L2 = new Label("本地地址:");
// 创建一个按钮
JButton startButton = new JButton("开始下载");
// 加载按钮监听事件
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
actionAdd();
}
});
// 初始化
tableModel = new Table();
// 创建一个表,构造 JTable,使用tableModel作为数据模型、默认的列模型和默认的选择模型对其进行初始化。
table = new JTable(tableModel);
// addListSelectionListener将侦听器添加到每次在选择发生更改时都得到通知的列表。
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
// valueChanged行选择更改时调用,重新绘制来显示新的选择
public void valueChanged(ListSelectionEvent e) {
// 调用tableSelectionChanged方法
tableSelectionChanged();
}
});
// SINGLE_SELECTION一次选择一个列表索引
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// 实例化进度条的类,并设置进度条的最小\最大值
Progress renderer = new Progress(0, 100);
// setStringPainted默认显示有界区间整数值的组件。进度条通常通过显示某个操作的完成百分比,
// 可能是此百分比的一个文本显示来传达其进度。
renderer.setStringPainted(true); // show progress text
table.setDefaultRenderer(JProgressBar.class, renderer);
// 设置表格的行高
table.setRowHeight((int) renderer.getPreferredSize().getHeight());
JPanel downloadsPanel = new JPanel();
downloadsPanel.setLayout(new BorderLayout());
downloadsPanel.add(new JScrollPane(table), BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel();
addPanel.add(L1);
addPanel.add(t1);
addPanel.add(L2);
addPanel.add(t2);
buttonsPanel.add(startButton);
// 为暂停按钮设置监听事件
pauseButton = new JButton("暂停下载");
pauseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 调用暂停方法
actionPause();
}
});
// 设置暂停按钮的初使状态为FALSE
pauseButton.setEnabled(false);
buttonsPanel.add(pauseButton);
// 为继续下载按钮设置监听事件,
resumeButton = new JButton("继续下载");
resumeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 调用恢复下载的方法
actionResume();
}
});
// 初始状态为FALSE
resumeButton.setEnabled(false);
// 为取消下载按钮设置监听事件
buttonsPanel.add(resumeButton);
cancelButton = new JButton("取消下载");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 调用方法
actionCancel();
}
});
cancelButton.setEnabled(false);
// 设设置清除按钮的监听事件,并调用相应的方法
buttonsPanel.add(cancelButton);
clearButton = new JButton("清除下载");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
actionClear();
}
});
clearButton.setEnabled(false);
buttonsPanel.add(clearButton);
// getContentPane返回此窗体的 contentPane 对象
// 设置布局
getContentPane().setLayout(new BorderLayout());
getContentPane().add(addPanel, BorderLayout.NORTH);
getContentPane().add(downloadsPanel, BorderLayout.CENTER);
getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
}
// 按钮事件内容
private void actionAdd() {
// 由文本框接收url地址
URL verifiedUrl = verifyUrl(t1.getText());
String address = new String(t2.getText());
// 判断url地址是否为空
if (verifiedUrl != null && address != null) {
tableModel.addDownload(new Download(verifiedUrl, address));
// 覆盖本文框内容为空
t1.setText("");
t2.setText("");
} else {
JOptionPane.showMessageDialog(this,
"请输入正确的远程(和本地)地址(如:http://192.168.20.99; D:/youway)",
"远程(或本地)地址错误", JOptionPane.ERROR_MESSAGE);
}
}
// 对地址进行判断
private URL verifyUrl(String url) {
if (!url.toLowerCase().startsWith("http://"))
return null;
URL verifiedUrl = null;
try {
verifiedUrl = new URL(url);
} catch (Exception e) {
return null;
}
if (verifiedUrl.getFile().length() < 2)
return null;
return verifiedUrl;
}
private void tableSelectionChanged() {
if (selectedDownload != null)
selectedDownload.deleteObserver(Main.this);
if (!clearing) {
selectedDownload = tableModel.getDownload(table.getSelectedRow());
selectedDownload.addObserver(Main.this);
updateButtons();
}
}
private void actionPause() {
selectedDownload.pause();
updateButtons();
}
private void actionResume() {
selectedDownload.resume();
updateButtons();
}
private void actionCancel() {
selectedDownload.cancel();
updateButtons();
}
private void actionClear() {
clearing = true;
tableModel.clearDownload(table.getSelectedRow());
clearing = false;
selectedDownload = null;
updateButtons();
}
// 设置按钮是否可用
private void updateButtons() {
if (selectedDownload != null) {
int status = selectedDownload.getStatus();
// 利用switch,和下载状态设置按钮是不否可用
switch (status) {
case Download.DOWNLOADING:
pauseButton.setEnabled(true);
resumeButton.setEnabled(false);
cancelButton.setEnabled(true);
clearButton.setEnabled(false);
break;
case Download.PAUSED:
pauseButton.setEnabled(false);
resumeButton.setEnabled(true);
cancelButton.setEnabled(true);
clearButton.setEnabled(false);
break;
case Download.ERROR:
pauseButton.setEnabled(false);
resumeButton.setEnabled(true);
cancelButton.setEnabled(false);
clearButton.setEnabled(true);
break;
default:
pauseButton.setEnabled(false);
resumeButton.setEnabled(false);
cancelButton.setEnabled(false);
clearButton.setEnabled(true);
}
} else {
pauseButton.setEnabled(false);
resumeButton.setEnabled(false);
cancelButton.setEnabled(false);
clearButton.setEnabled(false);
}
}
public void update(Observable o, Object arg) {
if (selectedDownload != null && selectedDownload.equals(o))
updateButtons();
}
public static void main(String[] args) {
Main manager = new Main();
manager.setVisible(true);
}
}[/code]
[[i] 本帖最后由 sunflower 于 2008-4-24 23:34 编辑 [/i]]
用来下载的类
[code]package crazysheep;import java.io.*;
import java.net.*;
import java.util.*;
// 从URL地址下载文件到本地.
public class Download extends Observable implements Runnable {
// 下载的最大缓冲区为1024.
private static final int MAX_BUFFER_SIZE = 1024;
// 设置下载的各种状态.
public static final String STATUSES[] = { "Downloading", "Paused",
"Complete", "Cancelled", "Error" };
// 定义各种状态的代号
public static final int DOWNLOADING = 0;
public static final int PAUSED = 1;
public static final int COMPLETE = 2;
public static final int CANCELLED = 3;
public static final int ERROR = 4;
// 要下载的URL地址
private URL url;
// 下载文件的大小 bytes
private int size;
// 已经下载的文件文件的bytes
private int downloaded;
// 定义一个整形变量用来接受状态代码
private int status;
private String address;
// 构造器
public Download(URL url,String address) {
// 获取url参数
this.url = url;
this.address=address;
// 初始化文件大小为空
size = -1;
// 初始化文件已下载大小为0
downloaded = 0;
// 初始化文件下载状态为“下载中”
status = DOWNLOADING;
// 开始下载
download();
}
//返回url地址的字符串形式
public String getUrl() {
return url.toString();
}
//返回文件大小
public int getSize() {
return size;
}
//返回已下载文件百分比
public float getProgress() {
return ((float) downloaded / size) * 100;
}
//返回下载状态的整形代码
public int getStatus() {
return status;
}
//设置下载状态为暂停,当侦听器的目标已更改其状态时调用。
public void pause() {
status = PAUSED;
stateChanged();
}
//设置下载状态为下载中,
public void resume() {
status = DOWNLOADING;
stateChanged();
download();
}
//下载状态为取消下载
public void cancel() {
status = CANCELLED;
stateChanged();
}
//提示下载出错
private void error() {
status = ERROR;
stateChanged();
}
//开始下载时开始创建线程,进行下载
private void download() {
Thread thread = new Thread(this);
thread.start();
}
private String getFileName(URL url) {
//获得此 URL 的文件名
String fileName = url.getFile();
//在此对象表示的字符序列中最后一次出现该字符的索引,如果未出现该字符,则返回 -1
return fileName.substring(fileName.lastIndexOf('/') + 1);
}
public void run() {
RandomAccessFile file = null;
InputStream stream = null;
try {
// 链接到 URL.
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
Connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
// 连接服务器
connection.connect();
// 检查服务器返回是不是有错
if (connection.getResponseCode() / 100 != 2) {
error();
}
// 检查文件是不是有错
int contentLength = connection.getContentLength();
if (contentLength < 1) {
error();
}
// 设置下载标志size
if (size == -1) {
size = contentLength;
stateChanged();
}
// 打开文件,到末尾
file = new RandomAccessFile(address+getFileName(url),"rw");
file.seek(downloaded);
stream = connection.getInputStream();
while (status == DOWNLOADING) {
// 设置buffer的大小为还剩下多少文件要下载
byte buffer[];
if (size - downloaded > MAX_BUFFER_SIZE) {
buffer = new byte[MAX_BUFFER_SIZE];
} else {
buffer = new byte[size - downloaded];
}
// 从服务器下载数据到buffer.
int read = stream.read(buffer);
if (read == -1)
break;
// 将buffer写入到文件
file.write(buffer, 0, read);
downloaded += read;
stateChanged();
}
// 如果下载完毕更改下载标志 完成
if (status == DOWNLOADING) {
status = COMPLETE;
stateChanged();
}
} catch (Exception e) {
error();
} finally {
// 关闭文件
if (file != null) {
try {
file.close();
} catch (Exception e) {
}
}
// 关闭下载流
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
}
}
}
}
// 通知 observers 下载的状态变了
private void stateChanged() {
setChanged();
//并调用 clearChanged 方法来指示此对象不再改变
notifyObservers();
}
}[/code]
进度条
[code]package crazysheep;import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
class Progress extends JProgressBar implements TableCellRenderer {
// 创建具有指定最小值和最大值的水平进度条
public Progress(int min, int max) {
super(min, max);
}
//此接口定义了要成为 JTable 中单元格渲染器的任意对象所需的方法。
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
// 设置进度条
setValue((int) ((Float) value).floatValue());
return this;
}
}[/code] [code]package crazysheep;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
//用来管理表内数据
class Table extends AbstractTableModel implements Observer {
// 建立一个数组columnNames用表每行每列的名字
private static final String[] columnNames = { "下载地址", "文件大小", "下载进度",
"下载状态" };
// 建立一个数组columnClasses用来存放表内所放数据的类型
private static final Class[] columnClasses = { String.class, String.class,
JProgressBar.class, String.class };
// 创建一个长度可伸缩的数组用来存放table 的下载列表
private ArrayList downloadList = new ArrayList();
public void addDownload(Download download) {
// 设置table为download改变事件的接收容器Oberser
download.addObserver(this);
// 将文件的下载列表加入到download容器
downloadList.add(download);
// 通知table表格发生了变化,通知所有侦听器,已插入范围的行。
fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
}
// 创建了一个返回值为Download的方法,返回列表上对应的下载地址
public Download getDownload(int row) {
return (Download) downloadList.get(row);
}
// 清除表中列表上对应项
public void clearDownload(int row) {
downloadList.remove(row);
// 通知所有侦听器,已删除范围在 [Row,Row](包括)的行。
fireTableRowsDeleted(row, row);
}
// 返回列模型中的列数
public int getColumnCount() {
return columnNames.length;
}
// 返回列名称。
public String getColumnName(int col) {
return columnNames[col];
}
// 返回表中数据类型
public Class getColumnClass(int col) {
return columnClasses[col];
}
// 定义一个getRowCount方法,返回此表模型中的行数。
public int getRowCount() {
// 返回下载列表中的大小
return downloadList.size();
}
// 返回 行 和 列 位置的单元格值。
public Object getValueAt(int row, int col) {
// 创建一个对象,强制转换下载列表上的行来获取URL地址
Download download = (Download) downloadList.get(row);
// 按顺序获取相应的内容
switch (col) {
// URL地址
case 0:
return download.getUrl();
// 文件大小
case 1:
//定义一个整形来接收文件大小
int size = download.getSize();
//如果文件大小不为空则返回文件大小
return (size == -1) ? "" : Integer.toString(size);
// 当前状态
case 2:
return new Float(download.getProgress());
// 下载进度
case 3:
//显示当前进度
return Download.STATUSES[download.getStatus()];
}
//如果都不符合则返回空
return "";
}
//创建一个方法,用来监视downloadList,一旦改变马上调用此方法
public void update(Observable o, Object arg) {
int index = downloadList.indexOf(o);
// 通知table 那行数据需要更新了
fireTableRowsUpdated(index, index);
}
}[/code] 把4个类合在一起运行,就可以下载了。可以是同时下载不同资源,支持暂停、继续和清除下载
[[i] 本帖最后由 sunflower 于 2008-4-24 23:43 编辑 [/i]] 受教了!~~回头研究下!~~谢谢楼主分享!~~ 厉害······一会儿我试试~呵呵~
四个一起运行······这个有点晕······ 我只有顶你的份………………::18:: ::18:: ::18:: ::18:: 正学,看看
……
页:
[1]
