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(); } } }