使用java多线程机制实现下载

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
/**
* HTTP的多线程下载工具。
* 
* @author 赵学庆 www.java2000.net
*/
public class HTTPDownloader extends Thread {

  private String page;
  // 保存的路径
  private String savePath;
  // 线程数
  private int threadNumber = 2;
  // 来源地址
  private String referer;
 // 最小的块尺寸。如果文件尺寸除以线程数小于这个,则会减少线程数。
  private int MIN_BLOCK = 10 * 1024;
  public static void main(String[] args) throws Exception {
    HTTPDownloader d = new HTTPDownloader("http://sdn.kugou.com/link.aspx?id=3480&url=http%3a%2f%2fdownmini.kugoo.com%2fKuGou2010.exe", "d://a.exe", 10);
    d.down();
  }
  public void run() {
    try {
      down();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**
   * 下载操作
   *  
   * @throws Exception
   */
  public void down() throws Exception {
    URL url = new URL(page); // 创建URL
    URLConnection con = url.openConnection(); // 建立连接
 int contentLen = con.getContentLength(); // 获得资源长度
    if (contentLen / MIN_BLOCK + 1 < threadNumber) {
      threadNumber = contentLen / MIN_BLOCK + 1; // 调整下载线程数
    }
    if (threadNumber > 10) {
      threadNumber = 10;
    }
    int begin = 0;
    int step = contentLen / threadNumber;
    int end = 0;
    for (int i = 0; i < threadNumber; i++) {
      end += step;
      if (end > contentLen) {
        end = contentLen;
      }
      new HTTPDownloaderThread(this, i, begin, end).start();
      begin = end;
    }
  }
  public HTTPDownloader() {
  }
  /**
   * 下载
   *  
   * @param page 被下载的页面
   * @param savePath 保存的路径
   */
  public HTTPDownloader(String page, String savePath) {
    this(page, savePath, 10);
  }
  /**
   * 下载
   *  
   * @param page 被下载的页面
   * @param savePath 保存的路径
   * @param threadNumber 线程数
   */
  public HTTPDownloader(String page, String savePath, int threadNumber) {
    this(page, page, savePath, 10);
  }
  /**
   * 下载
   *  
   * @param page 被下载的页面
   * @param savePath 保存的路径
   * @param threadNumber 线程数
   * @param referer 来源
   */
  public HTTPDownloader(String page, String referer, String savePath, int threadNumber) {
    this.page = page;
    this.savePath = savePath;
    this.threadNumber = threadNumber;
    this.referer = referer;
  }
  public String getPage() {
    return page;
  }
  public void setPage(String page) {
    this.page = page;
  }
  public String getSavePath() {
    return savePath;
  }
  public void setSavePath(String savePath) {
    this.savePath = savePath;
  }
  public int getThreadNumber() {
    return threadNumber;
  }
  public void setThreadNumber(int threadNumber) {
    this.threadNumber = threadNumber;
  }
  public String getReferer() {
    return referer;
  }
  public void setReferer(String referer) {
    this.referer = referer;
  }
}
/**
* 下载线程
*  
* @author 赵学庆 www.java2000.net
*/
class HTTPDownloaderThread extends Thread {
  HTTPDownloader manager;
  int startPos;
  int endPos;
  int id;
  int curPos;
  int BUFFER_SIZE = 4096;
  int readByte = 0;
  HTTPDownloaderThread(HTTPDownloader manager, int id, int startPos, int endPos) {
    this.id = id;
    this.manager = manager;
    this.startPos = startPos;
    this.endPos = endPos;
  }
  public void run() {
    // System.out.println("线程" + id + "启动");
    // 创建一个buff
    BufferedInputStream bis = null;
    RandomAccessFile fos = null;
    // 缓冲区大小
    byte[] buf = new byte[BUFFER_SIZE];
    URLConnection con = null;
    try {
      File file = new File(manager.getSavePath());
      // 创建RandomAccessFile
      fos = new RandomAccessFile(file, "rw");
      // 从startPos开始
      fos.seek(startPos);
      // 创建连接,这里会为每个线程都创建一个连接
      URL url = new URL(manager.getPage());
      con = url.openConnection();
      con.setAllowUserInteraction(true);
      curPos = startPos;
      // 设置获取资源数据的范围,从startPos到endPos
      con.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
      // 盗链解决
      con.setRequestProperty("referer", manager.getReferer() == null ? manager.getPage() : manager.getReferer());
      con.setRequestProperty("userAgent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
      // 下面一段向根据文件写入数据,curPos为当前写入的未知,这里会判断是否小于endPos,
      // 如果超过endPos就代表该线程已经执行完毕
      bis = new BufferedInputStream(con.getInputStream());
      while (curPos < endPos) {
        int len = bis.read(buf, 0, BUFFER_SIZE);
        if (len == -1) {
          break;
        }
        fos.write(buf, 0, len);
        curPos = curPos + len;
        if (curPos > endPos) {
          // 获取正确读取的字节数
          readByte += len - (curPos - endPos) + 1;
        } else {
          readByte += len;
        }
      }
      // System.out.println("线程" + id + "已经下载完毕:" + readByte);
      bis.close();
      fos.close();
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
}

 

 

 

抄的别人的 , 自己写的有问题。学习一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值