- 多线程下载
public class MultiThreadDownloader { private URL url; // 目标地址 private File file; // 本地文件 private long threadLen; // 每个线程下载多少 private static final int THREAD_AMOUNT = 3; // 线程数 private static final String DIR_PATH = "F:/Download"; // 下载目录 public MultiThreadDownloader(String address) throws IOException { // 记住下载地址 url = new URL(address); // 截取地址中的文件名, 创建本地文件 file = new File(DIR_PATH, address.substring(address.lastIndexOf("/") + 1)); } public void download() throws IOException { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(3000); // 获取文件总长度 long totalLen = conn.getContentLength(); // 计算每个线程要下载的长度 // 总长度 如果能整除 线程数, 每条线程下载的长度就是 总长度 / 线程数 // 总长度 如果不能整除 线程数, 那么每条线程下载长度就是 总长度 / 线程数 + 1 threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT; // 在本地创建一个和服务端大小相同的文件 RandomAccessFile raf = new RandomAccessFile(file, "rw"); // 设置文件的大小, 写入了若干个0 raf.setLength(totalLen); raf.close(); // 按照线程数循环 for (int i = 0; i < THREAD_AMOUNT; i++) { // 开启线程, 每个线程将会下载一部分数据到本地文件中 new DownloadThread(i).start(); } } private class DownloadThread extends Thread { // 用来标记当前线程是下载任务中的第几个线程 private int id; public DownloadThread(int id) { this.id = id; } public void run() { // 从临时文件读取当前线程已完成的进度 long start = id * threadLen; long end = id * threadLen + threadLen - 1; System.out.println("线程" + id + ": " + start + "-" + end); try { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(3000); // 设置当前线程下载的范围(start和end都包含) conn.setRequestProperty("Range", "bytes=" + start + "-" + end); InputStream in = conn.getInputStream(); // 随机读写文件, 用来向本地文件写出 RandomAccessFile raf = new RandomAccessFile(file, "rw"); // 设置保存数据的位置 raf.seek(start); // 每次拷贝100KB byte[] buffer = new byte[1024 * 100]; int len; while ((len = in.read(buffer)) != -1) { // 从服务端读取数据, 写到本地文件 raf.write(buffer, 0, len); } raf.close(); System.out.println("线程" + id + "下载完毕"); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new MultiThreadDownloader("http://192.168.1.240:8080/14.Web/android-sdk_r17-windows.zip").download(); } }
- 断点下载
public class BreakpointDownloader { // 下载目录 private static final String DIR_PATH = "F:/Download"; // 总线程数 private static final int THREAD_AMOUNT = 3; // 目标下载地址 private URL url; // 本地文件 private File dataFile; // 用来存储每个线程下载的进度的临时文件 private File tempFile; // 每个线程要下载的长度 private long threadLen; // 总共完成了多少 private long totalFinish; // 服务端文件总长度 private long totalLen; // 用来记录开始下载时的时间 private long begin; public BreakpointDownloader(String address) throws IOException { url = new URL(address); dataFile = new File(DIR_PATH, address.substring(address.lastIndexOf("/") + 1)); tempFile = new File(dataFile.getAbsolutePath() + ".temp"); } public void download() throws IOException { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(3000); totalLen = conn.getContentLength(); threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT; if (!dataFile.exists()) { RandomAccessFile raf = new RandomAccessFile(dataFile, "rws"); raf.setLength(totalLen); raf.close(); } if (!tempFile.exists()) { RandomAccessFile raf = new RandomAccessFile(tempFile, "rws"); for (int i = 0; i < THREAD_AMOUNT; i++) raf.writeLong(0); raf.close(); } for (int i = 0; i < THREAD_AMOUNT; i++) { new DownloadThread(i).start(); } // 记录开始时间 begin = System.currentTimeMillis(); } private class DownloadThread extends Thread { // 用来标记当前线程是下载任务中的第几个线程 private int id; public DownloadThread(int id) { this.id = id; } public void run() { try { RandomAccessFile tempRaf = new RandomAccessFile(tempFile, "rws"); tempRaf.seek(id * 8); long threadFinish = tempRaf.readLong(); synchronized(BreakpointDownloader.this) { totalFinish += threadFinish; } long start = id * threadLen + threadFinish; long end = id * threadLen + threadLen - 1; System.out.println("线程" + id + ": " + start + "-" + end); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(3000); conn.setRequestProperty("Range", "bytes=" + start + "-" + end); InputStream in = conn.getInputStream(); RandomAccessFile dataRaf = new RandomAccessFile(dataFile, "rws"); dataRaf.seek(start); byte[] buffer = new byte[1024 * 100]; int len; while ((len = in.read(buffer)) != -1) { dataRaf.write(buffer, 0, len); threadFinish += len; tempRaf.seek(id * 8); tempRaf.writeLong(threadFinish); synchronized(BreakpointDownloader.this) { totalFinish += len; } } dataRaf.close(); tempRaf.close(); System.out.println("线程" + id + "下载完毕"); // 如果已完成长度等于服务端文件长度(代表下载完成) if (totalFinish == totalLen) { System.out.println("下载完成, 耗时: " + (System.currentTimeMillis() - begin)); // 删除临时文件 tempFile.delete(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new BreakpointDownloader("http://192.168.1.240:8080/14.Web/android-sdk_r17-windows.zip").download(); } }