⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 downloader.java

📁 一个Mp3在线搜索器
💻 JAVA
字号:
/* * To change this template, choose Tools | Templates * and open the template in the editor. */package biz.tbuy.huliqing.jloading.downloader;import biz.tbuy.huliqing.jloading.Elog;import biz.tbuy.huliqing.jloading.TaskManager;import java.io.File;import java.io.IOException;import java.net.URL;import java.util.ArrayList;import java.util.List;import java.util.Timer;import java.util.TimerTask;import java.util.Vector;/** * * @author huliqing */public class Downloader {    private Config config;  // 状态保存配置文件    private String taskid;      // 任务标识    private String name;    // 短文件名(不包含后缀及路径)    private String url;     // 下载源地址    private File fileSave;  // 保存路径    private File fileProcess;//正在下载中的文件名(默认比原文件名多带一个"_")    private int threads;    // 下载的线程数        private boolean isFirst = true;    // 是否为首次下载(需要创建状态文件)    private boolean isInit = false;     // 是否已经初始化.    private long totalBytes;// 总文件大小    private long readBytes; // 已经读取的大小    private long readBytesNow;  // 当次启动后所读的字节数        // 待完成的任务列表    private Vector<Piece> tasks = new Vector<Piece>();    // 当前的所有任务列表,包括正在处理中的与待完成的任务列表    private Vector<Piece> tasksAll = new Vector<Piece>();        // 空闲的任务线程    private Vector<PieceLoader> frees = new Vector<PieceLoader>();    // 所有执行线程,包括执行的与空闲的    private List<PieceLoader> loaders = new ArrayList<PieceLoader>();        // 运行状态信息    private int state = 0;    private final static int STATE_NONE = 0;    private final static int STATE_READY = 1;    private final static int STATE_LOADING = 2;    private final static int STATE_PAUSED = 3;    private final static int STATE_STOPPED = 4;    //private final static int STATE_OK = 5;        // -------------------------------------------------- 构造        /**     * 使用状态文件进行断点续传     * @param config     */    public Downloader(Config config) {        this.config = config;                taskid = config.getId();        name = config.getName();        url = config.getURLs().get(0);        fileSave = new File(config.getSave());        threads = config.getThreads();        totalBytes = config.getLength();    // 1 文件长度                List<Piece> pieces = config.loadPieces();   // 2 任务列表        //System.out.println("pieces=" + pieces.size());        for (Piece p : pieces) {            tasksAll.add(p);            tasks.add(p);        }        // 初始化已读文件的长度,将文件长度减去未读的文件长度,即是已读的长度        for (Piece p : tasksAll) {            readBytes += (p.getPos() - p.getStart());        }        readBytes += pieces.size();        //System.out.println("readBytes=" + readBytes);        // 标识为“已初始化”“续传操作(因有Config文件)”        isInit = true;        isFirst = false;        state = STATE_READY;    }        /**     * 新建任务方式进行下载     * @param name     * @param url     * @param save     * @param threads     * @throws java.lang.Exception     */    public Downloader(String taskid, String name, String url, String save, int threads) {        this.taskid = taskid;        this.name = name;        this.url = url;        this.fileSave = new File(save);        this.threads = threads;        new Thread(new Runnable(){            public void run() {                init0();            }        }).start();    }    /** 首次下载文件(即非使用Config文件的方式),需要初始化相关信息 */    private void init0() {        // 对文件进行分块        try {            totalBytes = new URL(url).openConnection().getContentLength();            if (totalBytes == -1) state = STATE_NONE;        } catch (IOException ioe) {            return;        }        // 创建分块,并创建相应的负责下载的线程        long pieceSize = (long) Math.ceil((double) totalBytes / (double) threads);        long pStart = 0;        long pEnd = 0;        tasksAll.clear();        tasks.clear();        for (int i = 0; i < threads; i++) {            if (i == 0) {                pStart = pieceSize * i;            }            if (i == threads - 1) {                pEnd = totalBytes;            } else {                pEnd = pStart + pieceSize;            }            Piece piece = new Piece(pStart, pStart, pEnd);            tasksAll.add(piece);            tasks.add(piece);            pStart = pEnd + 1;        }        // 标识为“已初始化”“首次下载”        isInit = true;        isFirst = true;        state = STATE_READY;    }        // 创建状态保存文件    private synchronized void checkAndCreateConfig() {        int n = 0;        try {            // 判断是否为首次下载,如果是,则需要判断是否存在同名的文件,若存在同            // 名的文件,则重新更新保存路径            if (isFirst) {                String path = fileSave.getAbsolutePath();                String f_head = path.substring(0, path.lastIndexOf("."));                String f_suffix = path.substring(path.lastIndexOf(".")); // 含"."                File f1 = new File(path);               // 最终保存文件                File f2 = new File(path + "_");         // 未完成任务之前的文件名                File f3 = new File(path + "_config");   // 状态保存文件                // 检查并确保不存在相同名称的文件名,saveChange标识(存在相同的文件名)                while (f1.exists() || f2.exists() || f3.exists()) {                    n++;                    path = f_head + "[" + n + "]" + f_suffix;                    f1 = new File(path);                    f2 = new File(path + "_");                    f3 = new File(path + "_config");                }                try {                    f2.createNewFile();                } catch (Exception e) {                }                fileSave = f1;                fileProcess = f2;                isFirst = false;                   // 创建状态文件,并保存,字段分别为                // 任务标识, 文件名,下载源,保存路径,文件大小, 线程数                config = ConfigFactory.createConfig(                        taskid, name, url, fileSave.getAbsolutePath(), totalBytes, threads);                config.savePieces(tasksAll);                // 更新任务列表中的信息                TaskManager.getInstance().updateConfigPath(config);            } else {                fileProcess = new File(fileSave.getAbsolutePath() + "_");            }        } catch (Exception e) {            Elog.log("出错:创建配置文件是遇到问题!" + getClass().getName());        }    }        private void loading() {        // 初始化下载线程(先清除,以确保没有不可用的线程)        loaders.clear();        for (int i = 0; i < threads; i++) {            PieceLoader pl = new PieceLoader(this, tasks);            pl.start();            loaders.add(pl);        }                // 初始化定时器,每10秒保存一次状态        timer = new Timer();        timer.schedule(new MyTimerTask(), 0, 1000 * 10);    }        // ------------------------------------------------------------ 状态信息    /** 状态未知 */    public boolean isNone() {        return state == STATE_NONE ? true : false;    }        /** 是否运行中的 */    public boolean isLoading() {        return state == STATE_LOADING ? true : false;    }        /** 是否准备就绪的 */    public boolean isReady() {        return state == STATE_READY ? true : false;    }        /** 是否暂停中的 */    public boolean isPaused() {        return state == STATE_PAUSED ? true : false;    }        /** 是否已经停止的 */    public boolean isStopped() {        return state == STATE_STOPPED ? true : false;    }        /** 判断文件是否已经全部下载完 */    public synchronized boolean isOk() {        return (readBytes >= totalBytes);    }        // ------------------------------------------------------------ 任务控制        /** 开始下载任务 */    public void toStart() {        if (isLoading()) {            //System.out.println("正在运行中");            return;        } else if (isPaused()) {    // 暂停中的...            //System.out.println("暂停转为运行...");            state = STATE_LOADING;            for (PieceLoader pl : loaders) {                pl.toContinue();            }        } else {            //System.out.println("直接运行");            // 如果还从未下载过数据,则完全初始化            if (!isInit) init0();            // 检查相应的文件是否存在,确保不会出现重名文件            checkAndCreateConfig();            // 开始下载            state = STATE_LOADING;            loading();        }    }        /** 暂停任务 */    public void toPause() {        state = STATE_PAUSED;    }        /** 停止任务,如果任务已经完成,则重命名文件名*/    public synchronized void toStop() {        try {            if (isLoading() || isPaused()) {                timer.cancel();                config.savePieces(tasksAll);                state = STATE_STOPPED;                for (PieceLoader pl : loaders) {                    pl.interrupt();                }            }        } catch (Exception exception) {        }    }        /** 删除下载任务 */    public boolean toDelete() {        toStop();        if (fileProcess != null && fileProcess.exists()) {            fileProcess.delete();        }        if (config != null) {            config.delete();            TaskManager.getInstance().deleteConfig(config.getId());        }        TaskManager.getInstance().removeTask(taskid);        return true;    }        /** 处理已经完成的任务 */    public synchronized void processWhenOk() {        timer.cancel();        fileProcess.renameTo(fileSave);        config.delete();        TaskManager.getInstance().deleteConfig(config.getId());        TaskManager.getInstance().removeTask(taskid);        //System.out.println("切片数:" + tasksAll.size());        //System.out.println("读取数据ReadBytes:" + readBytes);    }        // ------------------------------------------------------------ 任务处理        /** 将一个新的任务区域(待完成的)添加到列表中,tasks, tasksAll */    public synchronized void addTask(Piece piece) {        this.tasksAll.add(piece);        this.tasks.add(piece);        config.savePieces(tasksAll);        //System.out.println("tasksAll.size=" + tasksAll.size());        //System.out.println("tasks.size=" + tasks.size());    }        /**     * 增加已读的字节数,下载线程每次读写完一段数据后都会调用该方法     * @param readBytes     */    public synchronized void growReadBytes(long bytes) {        readBytesNow += bytes;        readBytes += bytes;    }        /** 是否有空的任务线程 */    public synchronized boolean isFreeLoader() {        return frees.size() > 0;    }        /** 添加一个空闲的任务线程 */    public synchronized void addFreeLoader(PieceLoader pl) {        frees.add(pl);    }        /** 移除一个空闲线程 */    public synchronized void removeFreeLoader(PieceLoader pl) {        frees.remove(pl);    }        // ------------------------------------------------------------ 任务状态信息        /** 获取任务的URL下载源地址 */    public String getURL() {        return url;    }        /** 获取下载任务的最终文件保存对象 */    public File getFileSave() {        return fileSave;    }        /** 获取下载中的文件对象 */    public File getFileProcess() {        return fileProcess;    }        /** 获取当次启动后已经读取的字节 */    public long getReadBytesNow() {        return readBytesNow;    }        /** 已经读取的总字节数(包括续传的) */    public long getReadBytes() {        return readBytes;    }        /** 获取总文件长度 */    public long getTotalBytes() {        return totalBytes;    }        /** 获取下载速度 (k/s) */    public long getSpeed() {        long sp = 0;        for (PieceLoader pl : loaders) {            sp += pl.getSpeed();        }        return sp;    }        // ------------------------------------------------------------ 偏移修正    private int repairCount;    // 修正次数    private long offsetTotal;   // 偏移量    public long getOffsetTotal() {        return offsetTotal;    }    public synchronized void setOffsetTotal(long offsetTotal) {        this.offsetTotal = offsetTotal;    }    public int getRepairCount() {        return repairCount;    }    public synchronized void setRepairCount(int repairCount) {        this.repairCount = repairCount;    }        // ------------------------------------------------------------ 定时器        /**     * 任务定时器,每隔一段时间,这个定时器会把当前下载任务的各个分片(Piece)的状态     * 信息保存到磁盘文件中,以避免程序出现意外或突然蹦溃而造成的无法断点续传的功能     */    private Timer timer;        private class MyTimerTask extends TimerTask {        @Override        public void run() {            try {                if (isOk()) this.cancel();                config.savePieces(tasksAll);            } catch (Exception ex) {                //Elog.log("MyTimerTask");            }        }    }    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -