Java 多线程下载技术实现

本文介绍了如何使用Java实现多线程下载技术,通过文件分块、设置http Range请求头,利用RandomAccessFile实现每个线程下载指定部分。详细阐述了技术要点,包括线程分配、下载范围确定,并提供了简单的Java代码实现。
摘要由CSDN通过智能技术生成

多线程下载

多线程下载技术,简单的说就是把要下载的文件分成几块,由不同的线程来负责每一块数据的下载任务。

技术要点

  • RandomAccessFile
    Java中用来实现随机访问文件的类
  • http Range请求头

具体思路

1、文件分块。 文件分块大小(blockSize)= (文件大小 +线程数 - 1 )/ 线程数 ;
2、确定每一个线程所要下载的 文件的起始和结束位置。
现假设为每个线程分别编号:0,1, 2,3;则
第一个线程负责的下载位置是: 0*blockSize - (0+1)*blockSize -1,
第二个线程负责的下载位置是: 1*blockSize - (1+1)*blockSize -1,
以此类推第i个线程负责的下载位置是:i*blockSize - (i+1)*blockSize -1;
即线程(编号为id)下载开始位置 start = id*block;
即线程(编号为id)下载结束位置 end = (id+1)*block -1;
3、设置http 请求头, conn.setRequestProperty(“Range”, “bytes=” + start + “-” + end);

代码实现

一个简单的Java多线程下载代码如下:

package com.ricky.java.test.download;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Downloader {
   
    private URL url;    // 目标地址
    private File file;  // 本地文件
    private static final int THREAD_AMOUNT = 8;                 // 线程数
    private static final String DOWNLOAD_DIR_PATH = "D:/Download";      // 下载目录
    private int threadLen;                                      // 每个线程下载多少

    public Downloader(String address, String filename) throws IOException {     // 通过构造函数传入下载地址
        url = new URL(address);
        File dir = new File(DOWNLOAD_DIR_PATH);
        if(!dir.exists()){
            dir.mkdirs();
        }
        file = new File(dir, filename);
    }

    public void download() throws IOException {
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);

        int totalLen = conn.getContentLength();                             // 获取文件长度
        threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT;         // 计算每个线程要下载的长度

        System.out.println("totalLen="+totalLen+",threadLen:"+threadLen);

        RandomAccessFile raf = new RandomAccessFile(file, "rws");           // 在本地创建一个和服务端大小相同的文件
        raf.setLength(totalLen);                                            // 设置文件的大小
        raf.close();

        for (int i = 0; i < THREAD_AMOUNT; i++)                             // 开启3条线程, 每个线程下载一部分数据到本地文件中
            new DownloadThread(i).start();
    }

    private class DownloadThread extends Thread {
   
        private int id;
        public DownloadThread(int id) {
            this.id = id;
        }
        public void run() {
            int start = id * threadLen;                     // 起始位置
            int end = id * threadLen + threadLen - 1;       // 结束位置
            System.out.println("线程" + id + ": " + start + "-" + end);

            try {
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestProperty("Range", "bytes=" + start + "-" + end);     // 设置当前线程下载的范围

                InputStream in = conn.getInputStream();
                RandomAccessFile raf = new RandomAccessFile(file, "rws");
                raf.seek(start);            // 设置保存数据的位置

                byte[] buffer = new byte[1024];
                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 {

        String address = "http://dldir1.qq.com/qqfile/qq/QQ7.9/16621/QQ7.9.exe";
        new Downloader(address, "QQ7.9.exe").download();

//      String address = "http://api.t.dianping.com/n/api.xml?cityId=2";
//      new Downloader(address, "2.xml").download();
    }
}

封装多线程下载

文件下载是一个常用的模块,我们可以对其封装一下,方便以后调用。涉及到的开发技术如下:

  • JDK 1.7
  • Eclipse Juno
  • Maven 3
  • HttpClient 4.3.6

工程目录结构如下所示:
这里写图片描述

com.ricky.common.java.download.FileDownloader

package com.ricky.common.java.download;

import org.apache.log4j.Logger;

import com.ricky.common.java.download.config.FileDownloaderConfiguration;

/**
 * Java 文件多线程下载
 * @author Ricky Fung
 *
 */
public class FileDownloader {
   

    protected Logger mLogger = Logger.getLogger("devLog");

    private volatile static FileDownloader fileDownloader;

    private FileDownloaderEngine downloaderEngine;

    private FileDownloaderConfiguration configuration;

    public static FileDownloader getInstance(){

        if(fileDownloader==null){
            synchronized (FileDownloader.class) {
                if(fileDownloader==null){
                    fileDownloader = new FileDownloader();
                }
            }
        }

        return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值