• 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();
            }
        }
    }
  • 相关阅读:
    019_linuxC++之_函数模板引入
    018_linuxC++之_抽象类的引入
    017_linuxC++之_多态的引入
    《将博客搬至CSDN》
    016_linuxC++之_多重继承
    013_linuxC++之_派生类中权限的调整
    015_linuxC++之_覆写
    014_linuxC++之_不同类型的继承
    012_linuxC++之_类的继承定义
    011_linuxC++之_继承的引入
  • 原文地址:https://www.cnblogs.com/84126858jmz/p/4966348.html
Copyright © 2020-2023  润新知