Java实现多线程下载断点续传

Posted xuyiqing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现多线程下载断点续传相关的知识,希望对你有一定的参考价值。

开三个线程下载,代码:

package demo;

import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class MutilDownLoad {

    // 放在Tomcat下的一个文件
    static String path = "http://192.168.87.1:8080/lol.exe";

    // 多线程的个数(开3个线程)
    private static final int THREADACOUNT = 3;

    public static void main(String[] args) {
        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);

            int code = conn.getResponseCode();
            if (code == 200) {
                // 获取文件大小
                int length = conn.getContentLength();

                // 创建一个和服务器获取的文件大小一致的文件
                RandomAccessFile randomAccessFile = new RandomAccessFile("lol.exe", "rw");
                randomAccessFile.setLength(length);

                // 算出每个线程下载大小
                int blockSize = length / THREADACOUNT;

                // 计算每个线程的起始位置和结束位置
                for (int i = 0; i < THREADACOUNT; i++) {
                    int startIndex = i * blockSize;
                    int endIndex = (i + 1) * blockSize - 1;
                    // 处理最后一个线程结束位置
                    if (i == THREADACOUNT - 1) {
                        endIndex = length - 1;
                    }

                    // 开启多线程下载
                    new DowdLoadThread(startIndex, endIndex, i).start();

                }

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

    // 定义多线程下载文件
    private static class DowdLoadThread extends Thread {
        private int startIndex;
        private int endIndex;
        private int threadID;

        public DowdLoadThread(int startIndex, int endIndex, int threadID) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.threadID = threadID;
        }

        @Override
        public void run() {
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);

                // 设置
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

                int code = conn.getResponseCode();
                // 请求部分资源成功(206)
                if (code == 206) {
                    // 随机读写文件对象
                    RandomAccessFile randomAccessFile = new RandomAccessFile("lol.exe", "rw");

                    randomAccessFile.seek(startIndex);

                    InputStream in = conn.getInputStream();

                    // 当前线程下载的大小

                    int len = -1;
                    byte[] buffer = new byte[1024];
                    while ((len = in.read(buffer)) != -1) {
                        randomAccessFile.write(buffer, 0, len);

                    }
                    randomAccessFile.close();

                    System.out.println("线程id:" + threadID + "已下载完毕");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}

 

 

执行:

技术分享图片

 

 

接下来实现断点续传:

package demo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class MutilDownLoad {

    // 定义下载的路径
    private static String path = "http://192.168.87.1:8080/lol.exe";

    // 假设开三个线程
    private static final int threadCount = 3;

    // 代表当前正在运行的线程
    private static int runningThread;

    public static void main(String[] args) {

        try {

            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            int code = conn.getResponseCode();
            if (code == 200) {

                int length = conn.getContentLength();

                runningThread = threadCount;

                System.out.println("length:" + length);

                RandomAccessFile rafAccessFile = new RandomAccessFile(getFilename(path), "rw");
                rafAccessFile.setLength(length);

                int blockSize = length / threadCount;

                for (int i = 0; i < threadCount; i++) {
                    int startIndex = i * blockSize;
                    int endIndex = (i + 1) * blockSize - 1;

                    if (i == threadCount - 1) {

                        endIndex = length - 1;

                    }

                    System.out.println("线程id:::" + i + "理论下载的位置" + ":" + startIndex + "-----" + endIndex);

                    DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i);
                    downLoadThread.start();

                }

            }

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

    }

    private static class DownLoadThread extends Thread {

        private int startIndex;
        private int endIndex;
        private int threadId;

        public DownLoadThread(int startIndex, int endIndex, int threadId) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.threadId = threadId;
        }

        @Override
        public void run() {

            try {
                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                conn.setRequestMethod("GET");

                conn.setConnectTimeout(5000);

                File file = new File(getFilename(path) + threadId + ".txt");
                if (file.exists() && file.length() > 0) {
                    FileInputStream fis = new FileInputStream(file);
                    BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
                    String lastPositionn = bufr.readLine();
                    int lastPosition = Integer.parseInt(lastPositionn);

                    startIndex = lastPosition + 1;

                    System.out.println("线程id::" + threadId + "真实下载的位置" + ":" + startIndex + "-----" + endIndex);

                    fis.close();
                }

                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

                int code = conn.getResponseCode();

                if (code == 206) {

                    RandomAccessFile raf = new RandomAccessFile(getFilename(path), "rw");

                    raf.seek(startIndex);

                    InputStream in = conn.getInputStream();

                    int len = -1;
                    byte[] buffer = new byte[1024 * 1024];// 1Mb

                    int total = 0;

                    while ((len = in.read(buffer)) != -1) {
                        raf.write(buffer, 0, len);

                        total += len;
                        // 实现断点续传 就是把当前线程下载的位置 给存起来 下次再下载的时候 就是按照上次下载的位置继续下载
                        // 存到一个普通的.txt文本中
                        int currentThreadPosition = startIndex + total;

                        RandomAccessFile raff = new RandomAccessFile(getFilename(path) + threadId + ".txt", "rwd");
                        raff.write(String.valueOf(currentThreadPosition).getBytes());
                        raff.close();

                    }
                    raf.close();

                    System.out.println("线程id:" + threadId + "---下载完毕了");

                    // 把.txt文件删除 每个线程具体什么时候下载完毕了 我们不知道

                    // 线程同步锁
                    synchronized (DownLoadThread.class) {
                        runningThread--;
                        if (runningThread == 0) {
                            // 所有的线程都执行完毕了 就把.txt文件删除
                            for (int i = 0; i < threadCount; i++) {
                                File delteFile = new File(getFilename(path) + i + ".txt");
                                delteFile.delete();
                            }

                        }
                    }

                }

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

        }
    }

    // 获取文件的名字
    public static String getFilename(String path) {

        int start = path.lastIndexOf("/") + 1;
        return path.substring(start);
    }

}

 

技术分享图片

以上是关于Java实现多线程下载断点续传的主要内容,如果未能解决你的问题,请参考以下文章

Android 多线程下载,断点续传,线程池

Python实现下载界面(带进度条,断点续传,多线程多任务下载等)

Android多线程断点续传下载原理及实现

Go 实战 :如何实现 HTTP 断点续传多线程下载?

Android(十五)多线程下载包括断点续传

多线程下载文件(支持暂停取消断点续传)