多线程下载视频

多线程下载视频
具体思路

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

实际代码实现:

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;

public class Downloader{
   //目标地址
   private URL url;
   //本地文件
   private File file;
   //线程数
   private static final int THREAD_AMOUNT = 10;
   //文件目标路径
   private String address;
   //文件本地路径
   private String downloadPath;

   public Downloader(String address, String downloadPath) {
       try{
           this.address = address;
           this.downloadPath = downloadPath;
           url = new URL(address);
           file = new File(downloadPath);
       }catch (Exception e){
           e.printStackTrace();
       }
   }

   void download(CountDownLatch countDownLatch) throws IOException {
       HttpURLConnection conn = (HttpURLConnection) url.openConnection();
       conn.setConnectTimeout(5000);
       //获取文件总长度
       int totalLen = conn.getContentLength();
       //计算每个线程要下载的长度
       int threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT;
       //在本地创建一个和服务端大小相同的文件
       RandomAccessFile raf = new RandomAccessFile(file, "rws");
       //设置文件的总大小
       raf.setLength(totalLen);
       raf.close();
       // 开启线程, 每个线程下载一部分数据到本地文件中
       for (int i = 0; i < THREAD_AMOUNT; i++) {
           new DownloadThread(i,countDownLatch,threadLen,url,file).start();
       }
   }

   public void downRedio(){
       try{
           //防止ssl错误
           System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,SSLv3");
           CountDownLatch countDownLatch = new CountDownLatch(THREAD_AMOUNT);
           new Downloader(address,downloadPath).download(countDownLatch);
           countDownLatch.await();
       }catch (Exception e){
           e.printStackTrace();
       }
   }
}


```java
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;

public class DownloadThread extends Thread {

   //当前线程数
   private int count;
   //用来计算线程是否已经结束
   private CountDownLatch countDownLatch;
   //每个线程下载多少
   private int threadLen;
   //路径url
   private URL url;
   //文件
   private File file;

   DownloadThread(int count,CountDownLatch countDownLatch,int threadLen,URL url,File file) {
       this.count = count;
       this.countDownLatch = countDownLatch;
       this.threadLen = threadLen;
       this.url = url;
       this.file = file;
   }

   public void run() {
       //起始位置
       int start = count * threadLen;
       //结束位置
       int end = count * threadLen + threadLen - 1;
       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();
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           //每次执行完成,线程数-1
           countDownLatch.countDown();
       }
   }
}

当不需要等线程全部执行完成后,再处理业务,那么可以去掉countDownLatch.countDown();

public class applicaiontTest(){
    @Test
    public void test2(){
    	 String downPath = "E:\\20200610202924.mp3";
        String fileUrl = "http://aa.oss-cn-cc.aliyuncs.com/20200610202924.mp3";
        //多线程下载视频
        new Downloader(fileUrl,downPath).downRedio();
    }
}

可以直接main方法执行,也可以使用@test

你可能感兴趣的:(spring,boot,IDEA,Spring,java,多线程)