多线程下载断点续传

多线程下载断点续传

这里写图片描述

多线程下载断点续传

1.了解一下多线程下载的思路

    思路:开启多个线程下载同一个文件,这样可以使我们的下载文件的速度加快。如果我们使用单一的线程去下载。下载速度慢。

断点续传

1.断点续传需要在下载过程中记录每条线程的下载进度

2.每次下载开始之前先读取数据库,查询是否有未完成的记录,有就继续下载,没有则创建新记录插入数据库

3.在每次向文件中写入数据之后,在数据库中更新下载进度

4.下载完成之后删除数据库中下载记录

多线程下载的步骤

(1)首先获得下载文件的长度,然后设置本地文件的长度。
HttpURLConnection.getContentLength();//获取下载文件的长度
RandomAccessFile file = new RandomAccessFile(“QQWubiSetup.exe”,”rwd”);
file.setLength(filesize);//设置本地文件的长度
(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如
例如10M大小,使用3个线程来下载,
线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,
如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止
代码如下:HttpURLConnection.setRequestProperty(“Range”, “bytes=2097152-4194303”);
(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFile threadfile = new RandomAccessFile(“QQWubiSetup.exe “,”rwd”);
threadfile.seek(2097152);//从文件的什么位置开始写入数据

多线程下载断点续传的源码:

/**
     * 开启线程的数量
     */
    static int threadCount=3;
    /**
     * 访问下载的路径
     */
    static String path="http://169.254.87.122:8080/baofeng.exe";
    static int threadFinished=0;
    public static void main(String[] args) {
        try {
            //创建URL对象  参数:设置路径
            URL url=new URL(path);
            //打开连接,通过强制类型转换HttpURLConnection
            HttpURLConnection connection=(HttpURLConnection) url.openConnection();
            //设置请求的方式
            connection.setRequestMethod("GET");
            //设置读取的时间
            connection.setReadTimeout(5000);
            //设置连接的时间
            connection.setConnectTimeout(5000);
            if (connection.getResponseCode()==200) {
                //拿到要下载文件的大小
                int length = connection.getContentLength();
                //指定临时文件的路径和文件名
                File file=new File(getFileName(path));
                //创建随机存储文件对象
                RandomAccessFile raf=new RandomAccessFile(file, "rwd");
                //设置临时文件的大小和服务器的一模一样
                raf.setLength(length);
                //计算每个线程下载的字节数
                int size=length/threadCount;
                for (int i = 0; i <threadCount; i++) {
                    //计算3个线程的开始位置和结束位置
                    int startIndex=i*size;
                    int endIndex=(i+1)*size-1;
                    //如果是最后一个线程,那么结束位置特殊处理
                    if (i==threadCount-1) {
                        endIndex=length-1;
                    }
                    System.out.println("线程"+i+"-----------"+startIndex+"-------"+endIndex);
                    DowndLoadThread thread = new DowndLoadThread(i, startIndex, endIndex);
                    thread.start();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    /**
     * 得到文件名字的
     * @param path 传入的访问的路径
     * @return 返回处理后的结果
     */
    public  static String getFileName(String path){
        //找到最后/的索引
        int index = path.lastIndexOf("/");
        //进行截取
        return path.substring(index+1);

    } 
    static class DowndLoadThread extends Thread{
        int threadId;
        int startIndex;
        int endIndex;

        /**
         * 创建有参构造函数
         * @param threadId 第几个线程的
         * @param startIndex 开始的索引
         * @param endIndex   结束的索引
         */
        public DowndLoadThread( int threadId,int startIndex, int endIndex) {
            super();
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.threadId = threadId;
        }

        @Override
        public void run() {
            super.run();
            URL url;
            try {
                //设置线程从那个位置开始写入数据到临时文件
                File fileProgress=new File("h://"+threadId+".txt");
                //判断下载的临时文件是否存在
                if (fileProgress.exists()) {
                    FileInputStream fis=new FileInputStream(fileProgress);
                    BufferedReader br=new BufferedReader(new InputStreamReader(fis));
                    //拿到临时文件所存储的位置
                    int newStartIndex = Integer.parseInt(br.readLine());
                    startIndex=newStartIndex;
                    System.out.println("线程"+threadId+"最终位置---------------"+startIndex);
                }
                url = new URL(path);
                HttpURLConnection connection=(HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setReadTimeout(5000);
                connection.setConnectTimeout(5000);
                //设置请求数据的范围
                connection.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);

                if (connection.getResponseCode()==206) {
                    InputStream is = connection.getInputStream();
                    int len=0;
                    byte[] b=new byte[1024];
                    int total=0;
                    File file=new File("h://"+MuiltDownLoad.getFileName(path));
                    //创建随机文件的存储对象
                    RandomAccessFile raf=new RandomAccessFile(file, "rwd");
                    raf.seek(startIndex);
                    //记录当前下载进度
                    int currentPosition=startIndex;

                    while((len=is.read(b))!=-1){
                        //把下载下来的临时文件写入raf临时文件
                        raf.write(b, 0, len);
                        total+=len;
                        @SuppressWarnings("resource")
                        RandomAccessFile rafProgress=new RandomAccessFile(fileProgress, "rwd");
                        currentPosition=startIndex+total;
                        //把下载进度写入rafProgress临时文件,下一次下载时作为新的startIndex
                        rafProgress.write((currentPosition+"").getBytes());
                        System.out.println("线程"+threadId+"---------------"+total);
                    }
                    raf.close();
                    System.out.println("线程"+threadId+"下载完毕");
                    MuiltDownLoad.threadFinished++;
                    //如果这个条件成立,说明线程下载完毕
                    synchronized (MuiltDownLoad.path) {
                        if (MuiltDownLoad.threadFinished==MuiltDownLoad.threadCount) {
                            for (int i = 0; i < MuiltDownLoad.threadCount; i++) {
                                File temp=new File("h://"+i+".txt");
                                temp.delete();
                            }
                            MuiltDownLoad.threadFinished=0;
                        }
                    }


                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值