[Android开发]Android 多线程断点下载

  1. 多线程下载
    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();
    }
    }
    
  2. 断点下载
    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();
    }
    }
    
以上是[Android开发]Android 多线程断点下载的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>