多线程实现断点续存

原理

1.原理
其实很简单,无非是先获取要下的文件大小,然后在磁盘新建一个同样大小的文件,最后开几个线程分别下载文件的不同部分往磁盘写入。:p
2。实现
这只是一个简单的demo版本,存放下载信息的载体可以视情况使用配置文件和数据库(如:Android可以使用自带的sqlite)

一些说明:

  • 1.我为了模拟断点续存用了volatile 标志,每个线程下载4kb*1000后会自动停止并退出,这时候你可打开MP4文件发现后半部分是看不了的,因为还没下载 lol
  • 2.我下载的文件是我自己服务器上的,改下url就能下载了
  • 3.文件名的获取有些粗暴,这个有时间可以说下怎么解析比较好
  • 4.如果是大批多文件下载,可以建个线程池,扔里面下载,这样效率比较高
package servlet;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Properties;


/**
 * Created by Coder on 2017/1/19.
 */

public class FileDownload {
    //线程同步变量 退出线程的标志
    public volatile boolean isExited = false;

    //文件的下载地址
    private String fileUrl;

    //文件的存放路径
    private String filePath;

    //要下载的文件名
    private String filename;

    //文件的长度
    private long length;

    //下载文件的线程的数量
    private static final int threadCount = 4;

    //配置文件
    private Properties properties;

    //文件
    private File downloadFile;
    private File propertiesFile;


    public FileDownload(String url, String filePath){
        this.fileUrl = url;
        this.filePath = filePath;
        properties = new Properties();
    }

    //对下载工作进行初始化
    public void init(){
        HttpURLConnection conn = null;
        RandomAccessFile raf = null;
        try {
            //获取网络文件流
            URL url = new URL(fileUrl);
            conn = (HttpURLConnection)url.openConnection();
            conn.setConnectTimeout(3000);
            conn.setRequestMethod("GET");

//            if(conn.getResponseCode() == HttpStatus.sC_OK)
            //获取文件长度
            length = conn.getContentLength();
            //获取文件名,这里是截取URL的最后一个"\"的后面
            String str = conn.getURL().getFile();
            filename = str.substring(str.lastIndexOf('/')+1);

            if(length <= 0){
                return;
            }

            //创建本地文件路径
            File dir = new File(filePath);
            if(! dir.exists()){
                dir.mkdir();
            }

            downloadFile = new File(dir, filename);
          //初始化文件
            if(!downloadFile.exists() || downloadFile.length() != length){
                //将文件设置为要下载文件的大小
                raf = new RandomAccessFile(downloadFile, "rwd");
                raf.setLength(length);
            }

            propertiesFile = new File(dir, filename.substring(0, filename.lastIndexOf('.'))+".properties");
            //初始化配置文件
            if(!propertiesFile.exists() ){
                propertiesFile.createNewFile();
            }
            //第一次初始化配置文件时,往配置文件里写入文件信息
            if(propertiesFile.length() == 0){
                properties.setProperty("fileName", filename);
                properties.setProperty("fileUrl", fileUrl);
                properties.setProperty("filePath", filePath);
                properties.setProperty("fileLength", ""+length);
                for(int i=0; i<threadCount; i++){
                    if(i != threadCount-1){
                        properties.setProperty("thread"+i+"_start", ""+i*(length/threadCount));
                        properties.setProperty("thread"+i+"_end", ""+(i+1)*(length/threadCount));
                    }else{
                        properties.setProperty("thread"+i+"_start", ""+i*(length/threadCount));
                        properties.setProperty("thread"+i+"_end", ""+length);
                    }
                }
                FileOutputStream out = new FileOutputStream(propertiesFile);
                properties.store(out, "init my propertiesFile!!!");
            }
            //载入配置文件
            properties = new Properties();
            properties.load(new FileInputStream(propertiesFile));

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(raf != null){
                    raf.close();
                }
                if(conn != null){
                    conn.disconnect();                  
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public void download(){
        for(int i=0; i<threadCount; i++){
            System.out.println(properties.toString());
            System.out.println("thread"+i+"_start");
            long start = Long.parseLong(properties.getProperty("thread"+i+"_start"));
            long end = Long.parseLong(properties.getProperty("thread"+i+"_end"));
            if(i != threadCount-1){
                new DownloadThread("thread"+i, start, end).start();
            }else{
                new DownloadThread("thread"+i, start, end).start();
            }
            System.out.println("thread"+i+"已经启动!!!!!");
        }

    }

    public void pause(){
        isExited = !isExited;
    }

    class DownloadThread extends Thread{
        private String threadName;
        private long start;
        private long end;

        public DownloadThread(String threadName, long start, long end){
            this.threadName = threadName;
            this.start = start;
            this.end = end;
            System.out.println(threadName+" start: "+start+" end: "+end);
        }
        @Override
        public void run() {
            HttpURLConnection conn = null;
            BufferedInputStream in = null;
            FileOutputStream out = null;
            RandomAccessFile raf = null;
            try {
                //获取网络文件流
                URL url = new URL(fileUrl);
                conn = (HttpURLConnection)url.openConnection();
                conn.setConnectTimeout(3000);
                conn.setRequestMethod("GET");

                in = new BufferedInputStream(conn.getInputStream());
                in.skip(start);

                raf = new RandomAccessFile(downloadFile, "rwd");
                raf.seek(start);
                byte[] buf = new byte[1024 * 4];
                int len = -1;
                int count = 0;
                while ((len = in.read(buf)) != -1 && !isExited) {
                    if(start+len < end){//还未下载完成
                        raf.write(buf, 0, len);
                        start += len;
                        properties.setProperty(threadName+"_start", ""+start);
                        properties.setProperty(threadName+"_end", ""+end);
                    }else{//此线程要下载的已经下载完成
                        raf.write(buf, 0, (int)(end-start));
                        start = end;
                        properties.setProperty(threadName+"_start", ""+start);
                        properties.setProperty(threadName+"_end", ""+end);
                        break;
                    }
                    System.out.println(threadName+" start:"+start+" end:"+end);
                   count++;
                   if(count == 1000){
                       pause();
                   }
                }
                //将配置文件保存
                out = new FileOutputStream(propertiesFile);
                properties.store(out, "download my file !!");

            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    if(raf != null){
                        raf.close();
                    }
                    if(in != null){
                        in.close();                 
                    }
                    if(out != null){
                        out.flush();
                        out.close();
                    }
                    if(conn != null){
                        conn.disconnect();                  
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        FileDownload download = new FileDownload("http://192.168.1.107:8080/news/video/65.mp4", "D:/video/");
        download.init();
        download.download();        
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值