黑客X档案官方论坛's Archiver

sunflower 发表于 2008-4-24 23:29

一个简单的下载工具源代码(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]]

sunflower 发表于 2008-4-24 23:36

用来下载的类

[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]

sunflower 发表于 2008-4-24 23:37

进度条

[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]

sunflower 发表于 2008-4-24 23:38

[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]

sunflower 发表于 2008-4-24 23:38

把4个类合在一起运行,就可以下载了。可以是同时下载不同资源,支持暂停、继续和清除下载

[[i] 本帖最后由 sunflower 于 2008-4-24 23:43 编辑 [/i]]

xx52499 发表于 2008-4-25 15:34

受教了!~~回头研究下!~~谢谢楼主分享!~~

whitemouse 发表于 2008-4-26 17:33

厉害······一会儿我试试~呵呵~
四个一起运行······这个有点晕······

wangchangqing 发表于 2008-4-27 19:43

我只有顶你的份………………::18:: ::18:: ::18:: ::18::

ydzj 发表于 2008-4-28 15:51

正学,看看









……

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.