Java多线程下载文件

文件下载采用多线程方式能够充分利用CPU资源,关键点是设置线程的读取开始和结束位置。下面的代码,采用线程池启动10个线程来执行下载

 

 

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FileDownLoadTest {
 private static final int TCOUNT = 10;
 
 /** 10个线程 */
 private CountDownLatch latch = new CountDownLatch(TCOUNT);

 private long completeLength = 0;

 /**
  * 文件总长度,单位bytes
  */
 private long fileLength;

 public static void main(String[] args) throws Exception {
  new FileDownLoadTest().download("http://localhost:8080/test/IESSAction.docx");
 }

 public void download(String address) throws Exception {
  ExecutorService service = Executors.newFixedThreadPool(TCOUNT);
  URL url = new URL(address);
  URLConnection cn = url.openConnection();
  cn.setRequestProperty("Referer", "http://www.test.com");
  fileLength = cn.getContentLength();
  //每个线程读取的长度
  long packageLength = fileLength / TCOUNT;
  //文件平均分给10个线程读取,如果不能平均分配,则剩余的长度为leftLength
  long leftLength = fileLength % TCOUNT;
  RandomAccessFile file = new RandomAccessFile("d:\\test.docx", "rw");
  //计算每个线程请求文件的开始和结束位置
  long pos = 0;
  long endPos = pos + packageLength;
  for (int i = 0; i < TCOUNT; i++) {
   if (leftLength > 0) {
    endPos++;
    leftLength--;
   }
   service.execute(new DownLoadThread(url, file, pos, endPos));
   pos = endPos;
   endPos = pos + packageLength;
  }
  System.out.println("waiting........................................");
  long begin = System.currentTimeMillis();
  latch.await();
  file.close();
  System.out.println("end........................................");
  System.out.println(System.currentTimeMillis() - begin + "ms");
  service.shutdown();
 }

 class DownLoadThread implements Runnable {
  private URL url;
  private RandomAccessFile file;
  private long from;
  private long end;

  DownLoadThread(URL url, RandomAccessFile file, long from, long end) {
   this.url = url;
   this.file = file;
   this.from = from;
   this.end = end;
  }

  public void run() {
   long pos = from;
   byte[] buf = new byte[512];
   try {
    HttpURLConnection cn = (HttpURLConnection) url.openConnection();
    cn.setRequestProperty("Range", "bytes=" + from + "-" + end);
    if (cn.getResponseCode() != 200 && cn.getResponseCode() != 206) {
     run();
     return;
    }
    BufferedInputStream bis = new BufferedInputStream(cn.getInputStream());
    int len;
    while ((len = bis.read(buf)) != -1) {
     file.seek(pos);
     file.write(buf, 0, len);
     pos += len;
     completeLength += len;
     System.out.println("threadName: "
       + Thread.currentThread().getName() + "persent: "
       + completeLength * 100 / fileLength + "%");
    }
    cn.disconnect();
    latch.countDown();
   } catch (IOException e) {
    e.printStackTrace();

   }
  }
 }

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值