java实现多线程断点续传

断点续传的关键

这里只针对http协议。
1.http请求中可以设置RANGE属性,用来设置返回数据的其实位置和结束位置
2.每个线程对同一个文件,不同的位置进行写入。可用RandomAccessFile的seek(long pos)方法,设置文件读写的起始位置。
3当暂停下载时,需要保存每个线程下载的进度。写进中间文件。
4.继续下载时,读取上次下载的进度,继续下载。
本文代码部分复制于下网站
https://www.ibm.com/developerworks/cn/java/joy-down/index.html
SiteFileFetch: 负责整个下载任务的控制。
FileSplitterFetch :为SiteFileFetch的内部类,继承自Thread类。为下载任务的子任务。
SiteInfoBean :保存的路径,文件名,和url等基本信息
FileAccessI :对流的操作类
OptionDownTask :读取上次任务或中断任务是,写入中间文件的接口。
OptionDownTaskImpl:实现了OptionDownTask的接口,该类读取和保存中文件信息是基于对象流ObjectInputStream和ObjectOutputStream.
TaskPositionBean:用于保存下载进度的可序列化的对象。
TaskProgressBean:OptionDownTask接口的方法的传入或返回的实体类。

SiteFileFetch.java

/* 
 /*
 * SiteFileFetch.java 
 */
package com.net.program.breakpoint;

import java.io.*;
import java.net.*;
import java.text.NumberFormat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class SiteFileFetch extends Thread {
   
    SiteInfoBean siteInfoBean = null; // 文件信息 Bean
    long[] nStartPos; // 开始位置
    long[] nEndPos; // 结束位置
    FileSplitterFetch[] fileSplitterFetch; // 子线程对象
    long nFileLength; // 文件长度
    boolean bFirst = true; // 是否第一次取文件
    boolean bStop = false; // 停止标志
    File tmpFile; // 文件下载的临时信息
    DataOutputStream output; // 输出到文件的输出流
    OptionDownTask odt;
    static AtomicLong atomicLong;
    TaskProgressBean taskProgressBean;
    CountDownLatch countDownLatch;// 等所有线程执行完后,判断是否需要写入中间文件。

    public SiteFileFetch(SiteInfoBean bean, OptionDownTask odt) throws IOException {
        siteInfoBean = bean;
        // tmpFile = File.createTempFile ("zhong","1111",new
        // File(bean.getSFilePath()));
        tmpFile = new File(bean.getSFilePath() + File.separator + bean.getSFileName() + ".info");
        atomicLong = new AtomicLong();
        this.odt = odt;
        if (tmpFile.exists()) {
            bFirst = false;

            taskProgressBean = odt.readTask();// 读取上次下载进度
            nStartPos = taskProgressBean.getStarts();
            nEndPos = taskProgressBean.getEnds();
            // read_nPos();
        } else {
            nStartPos = new long[bean.getNSplitter()];
            nEndPos = new long[bean.getNSplitter()];
        }
        countDownLatch = new CountDownLatch(nStartPos.length);// 初始化阀门,值为,线程个数
    }

    public void run() {
        // 获得文件长度
        // 分割文件
        // 实例 FileSplitterFetch
        // 启动 FileSplitterFetch 线程
        // 等待子线程返回
        nFileLength = getFileSize();
        try {
            if (bFirst) {
  // 是否是第一次下载该文件,如果是分割任务
                // nFileLength = getFileSize();
                if (nFileLength == -1) {
                    System.err.println("File Length is not known!");
                } else if (nFileLength == -2) {
                    System.err.println("File is not access!");
                } else {
                    long threadDownSize = nFileLength / nStartPos.length;
                    for (int i = 0; i < nStartPos.length; i++) {
                        nStartPos[i] = (i == 0 ? 0 : (long) (i * threadDownSize) + 1);
                        nEndPos[i] = (i + 1) * threadDownSize;
                    }
                    /*
                     * for (int i = 0; i < nEndPos.length - 1; i++) { nEndPos[i]
                     * = nStartPos[i + 1]; }
                     */
                    nEndPos[nEndPos.length - 1] = nFileLength;
                }
            }
            // 启动子线程
            fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
            long remain = 0;
            for (int i = 0; i < nStartPos.length; i++) {
                remain += nEndPos[i] - nStartPos[i];
                fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
                        siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(), nStartPos[i],
                        nEndPos[i], i);
                Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);
                fileSplitterFetch[i].start();
            }

            // 初始化文件下载进度
            atomicLong.set(nEndPos[nEndPos.length - 1] - remain);

            // 用来读取控制台数据,如果输入stop,则停止当前任务,将停止表示设为true
            new Thread() {
                @Override
                public void run() {
  
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值