java多线程断点续传下载

断点续传就是利用临时文件,在下载的时候把每个线程下载的进度存到一个进度文件里,等下次再下载的时候直接从进度文件里读取这个值,然后+上开始时候的值继续下载就可以了

package down;

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 Down {

    static int threadCount = 3;
    //记录完成下载线程的个数
    static int finishThread = 0;
    static String path = "http://192.168.21.1:8080/ok/TGPSetup.exe";

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setReadTimeout(5000);
            conn.setConnectTimeout(5000);
            if (conn.getResponseCode() == 200) {
                // 第一次请求要下载的长度
                int length = conn.getContentLength();
                // 应该从字符串中截取文件名称
                File file = new File("TGPSetup.exe");
                // 在下载之前生成临时文件,占位置
                RandomAccessFile rdm = new RandomAccessFile(file, "rwd");
                // 给临时文件大小
                rdm.setLength(length);
                // 关闭
                rdm.close();
                // 计算每个线程应该下载的长度
                int size = length / threadCount;
                // 为每个线程分配开始位置和结束位置
                for (int i = 0; i < threadCount; i++) {
                    int start = i * size;
                    int end = (i + 1) * size - 1;
                    // 最后一个线程的结束位置为总长度
                    if (i == threadCount - 1) {
                        end = length;
                    }
                    // 每次都调用新的线程
                    new DownThread(start, end, i).start();
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

// 线程
class DownThread extends Thread {
    private int start;
    private int end;
    private int threadId;

    public DownThread(int start, int end, int threadId) {
        this.start = start;
        this.end = end;
        this.threadId = threadId;
    }

    @Override
    public void run() {
        try {
            //创建进度文件
            File progressFile = new File(threadId + ".txt");
            //判断是否有记录进度的文件,如果有的话把开始位置重新赋值
            if (progressFile.exists()) {
                FileInputStream fis = new FileInputStream(progressFile);
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        fis));
                start+=Integer.parseInt(br.readLine());
                fis.close();

            }
            System.out.println(threadId + "线程下载区间" + start + "---" + end);
            // 再次请求网络
            URL url = new URL(Down.path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setReadTimeout(5000);
            conn.setConnectTimeout(5000);
            // 设置本次请求的文件的长度
            conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
            // 请求部分数据是206
            if (conn.getResponseCode() == 206) {
                // 得到请求长度的文件输入流
                InputStream is = conn.getInputStream();
                byte[] b = new byte[1024];
                int len = 0;
                // 记录每一次下载字节数
                int totle = 0;
                // 应该从字符串中截取文件名称
                File file = new File("TGPSetup.exe");
                // 拿到之前占位置那个文件,相当于输出流
                RandomAccessFile rdm = new RandomAccessFile(file, "rwd");
                // 改变写入文件的开始位置
                rdm.seek(start);
                while ((len = is.read(b)) != -1) {
                    // 每次读取流里的数据写到临时文件里
                    rdm.write(b, 0, len);
                    totle += len;
                    //System.out.println(threadId + "线程" + "下载了" + totle);
                    //把下载的总数存到进度文件里
                    RandomAccessFile rdm1 = new RandomAccessFile(progressFile,
                            "rwd");
                    rdm1.write((totle + "").getBytes());
                    rdm1.close();
                }
                rdm.close();
                Down.finishThread++;
                //下载结束删除进度文件
                if(Down.finishThread==Down.threadCount){
                    //加同步锁
                    synchronized (Down.path) {
                        for (int i = 0; i < Down.threadCount; i++) {
                            File f = new File(i+".txt");
                            f.delete();
                        }
                        Down.finishThread = 0;
                    }
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
原文地址:https://www.cnblogs.com/84126858jmz/p/4966348.html