使用Apache HttpClient实现多线程下载的小例子

    xiaoxiao2021-12-14  15

    网上类似的文章很多,参考了很多人的,大部分人都是用URLConnection写的。

    原理一:HTTP多线程下载原理

    1、发送一个含有Rang头的Head请求,如果返回状态码为206,则允许多线程下载

     

    原理二:多线程下载原理

    1、使用HttpClient的Head请求获取请求文件的信息

    2、发送一个Rang的Head请求判断是否允许多线程下载

    3、通过主任务创建多个分段下载线程,分段下载文件,然后用Java的随机读写文件类保存下载的内容

     

    (等有时间了再添加内容吧,先简单写这么多)

    调度功能代码片段

    Java代码 /**   * 开始下载   * @throws Exception   */  public void startDown() throws Exception{       HttpClient httpClient = new DefaultHttpClient();       try {           //获取下载文件信息           getDownloadFileInfo(httpClient);           //启动多个下载线程           startDownloadThread();           //开始监视下载数据           monitor();       } catch (Exception e) {           throw e;       } finally {           httpClient.getConnectionManager().shutdown();       }   }     /**   * 获取下载文件信息   */  private void getDownloadFileInfo(HttpClient httpClient) throws IOException,           ClientProtocolException, Exception {       HttpHead httpHead = new HttpHead(url);       HttpResponse response = httpClient.execute(httpHead);       //获取HTTP状态码       int statusCode = response.getStatusLine().getStatusCode();         if(statusCode != 200throw new Exception("资源不存在!");       if(getDebug()){           for(Header header : response.getAllHeaders()){               System.out.println(header.getName()+":"+header.getValue());           }       }         //Content-Length       Header[] headers = response.getHeaders("Content-Length");       if(headers.length > 0)           contentLength = Long.valueOf(headers[0].getValue());         httpHead.abort();              httpHead = new HttpHead(url);       httpHead.addHeader("Range""bytes=0-"+(contentLength-1));       response = httpClient.execute(httpHead);       if(response.getStatusLine().getStatusCode() == 206){           acceptRanges = true;       }       httpHead.abort();   }     /**   * 启动多个下载线程   * @throws IOException   * @throws FileNotFoundException   */  private void startDownloadThread() throws IOException,           FileNotFoundException {       //创建下载文件       File file = new File(localPath);       file.createNewFile();       RandomAccessFile raf = new RandomAccessFile(file, "rw");       raf.setLength(contentLength);       raf.close();              //定义下载线程事件实现类       DownloadThreadListener listener = new DownloadThreadListener() {           public void afterPerDown(DownloadThreadEvent event) {               //下载完一个片段后追加已下载字节数               synchronized (object) {                   DownloadTask.this.receivedCount += event.getCount();               }           }             public void downCompleted(DownloadThreadEvent event) {               //下载线程执行完毕后从主任务中移除               threads.remove(event.getTarget());               if(getDebug()){                   System.out.println("剩余线程数:"+threads.size());               }           }       };              //不支持多线程下载时       if (!acceptRanges) {           if(getDebug()){               System.out.println("该地址不支持多线程下载");           }           //定义普通下载           DownloadThread thread = new DownloadThread(url, 0, contentLength, file, false);           thread.addDownloadListener(listener);           thread.start();           threads.add(thread);           return;       }              //每个请求的大小       long perThreadLength = contentLength / threadCount + 1;       long startPosition = 0;       long endPosition = perThreadLength;       //循环创建多个下载线程       do{           if(endPosition >= contentLength)               endPosition = contentLength - 1;             DownloadThread thread = new DownloadThread(url, startPosition, endPosition, file);           thread.addDownloadListener(listener);           thread.start();           threads.add(thread);             startPosition = endPosition + 1;//此处加 1,从结束位置的下一个地方开始请求           endPosition += perThreadLength;       } while (startPosition < contentLength);   }   [java] view plain copy print ? /**  * 开始下载  * @throws Exception  */  public void startDown() throws Exception{      HttpClient httpClient = new DefaultHttpClient();      try {          //获取下载文件信息          getDownloadFileInfo(httpClient);          //启动多个下载线程          startDownloadThread();          //开始监视下载数据          monitor();      } catch (Exception e) {          throw e;      } finally {          httpClient.getConnectionManager().shutdown();      }  }    /**  * 获取下载文件信息  */  private void getDownloadFileInfo(HttpClient httpClient) throws IOException,          ClientProtocolException, Exception {      HttpHead httpHead = new HttpHead(url);      HttpResponse response = httpClient.execute(httpHead);      //获取HTTP状态码      int statusCode = response.getStatusLine().getStatusCode();        if(statusCode != 200throw new Exception("资源不存在!");      if(getDebug()){          for(Header header : response.getAllHeaders()){              System.out.println(header.getName()+":"+header.getValue());          }      }        //Content-Length      Header[] headers = response.getHeaders("Content-Length");      if(headers.length > 0)          contentLength = Long.valueOf(headers[0].getValue());        httpHead.abort();            httpHead = new HttpHead(url);      httpHead.addHeader("Range""bytes=0-"+(contentLength-1));      response = httpClient.execute(httpHead);      if(response.getStatusLine().getStatusCode() == 206){          acceptRanges = true;      }      httpHead.abort();  }    /**  * 启动多个下载线程  * @throws IOException  * @throws FileNotFoundException  */  private void startDownloadThread() throws IOException,          FileNotFoundException {      //创建下载文件      File file = new File(localPath);      file.createNewFile();      RandomAccessFile raf = new RandomAccessFile(file, "rw");      raf.setLength(contentLength);      raf.close();            //定义下载线程事件实现类      DownloadThreadListener listener = new DownloadThreadListener() {          public void afterPerDown(DownloadThreadEvent event) {              //下载完一个片段后追加已下载字节数              synchronized (object) {                  DownloadTask.this.receivedCount += event.getCount();              }          }            public void downCompleted(DownloadThreadEvent event) {              //下载线程执行完毕后从主任务中移除              threads.remove(event.getTarget());              if(getDebug()){                  System.out.println("剩余线程数:"+threads.size());              }          }      };            //不支持多线程下载时      if (!acceptRanges) {          if(getDebug()){              System.out.println("该地址不支持多线程下载");          }          //定义普通下载          DownloadThread thread = new DownloadThread(url, 0, contentLength, file, false);          thread.addDownloadListener(listener);          thread.start();          threads.add(thread);          return;      }            //每个请求的大小      long perThreadLength = contentLength / threadCount + 1;      long startPosition = 0;      long endPosition = perThreadLength;      //循环创建多个下载线程      do{          if(endPosition >= contentLength)              endPosition = contentLength - 1;            DownloadThread thread = new DownloadThread(url, startPosition, endPosition, file);          thread.addDownloadListener(listener);          thread.start();          threads.add(thread);            startPosition = endPosition + 1;//此处加 1,从结束位置的下一个地方开始请求          endPosition += perThreadLength;      } while (startPosition < contentLength);  }   /** * 开始下载 * @throws Exception */ public void startDown() throws Exception{ HttpClient httpClient = new DefaultHttpClient(); try { //获取下载文件信息 getDownloadFileInfo(httpClient); //启动多个下载线程 startDownloadThread(); //开始监视下载数据 monitor(); } catch (Exception e) { throw e; } finally { httpClient.getConnectionManager().shutdown(); } } /** * 获取下载文件信息 */ private void getDownloadFileInfo(HttpClient httpClient) throws IOException, ClientProtocolException, Exception { HttpHead httpHead = new HttpHead(url); HttpResponse response = httpClient.execute(httpHead); //获取HTTP状态码 int statusCode = response.getStatusLine().getStatusCode(); if(statusCode != 200) throw new Exception("资源不存在!"); if(getDebug()){ for(Header header : response.getAllHeaders()){ System.out.println(header.getName()+":"+header.getValue()); } } //Content-Length Header[] headers = response.getHeaders("Content-Length"); if(headers.length > 0) contentLength = Long.valueOf(headers[0].getValue()); httpHead.abort(); httpHead = new HttpHead(url); httpHead.addHeader("Range", "bytes=0-"+(contentLength-1)); response = httpClient.execute(httpHead); if(response.getStatusLine().getStatusCode() == 206){ acceptRanges = true; } httpHead.abort(); } /** * 启动多个下载线程 * @throws IOException * @throws FileNotFoundException */ private void startDownloadThread() throws IOException, FileNotFoundException { //创建下载文件 File file = new File(localPath); file.createNewFile(); RandomAccessFile raf = new RandomAccessFile(file, "rw"); raf.setLength(contentLength); raf.close(); //定义下载线程事件实现类 DownloadThreadListener listener = new DownloadThreadListener() { public void afterPerDown(DownloadThreadEvent event) { //下载完一个片段后追加已下载字节数 synchronized (object) { DownloadTask.this.receivedCount += event.getCount(); } } public void downCompleted(DownloadThreadEvent event) { //下载线程执行完毕后从主任务中移除 threads.remove(event.getTarget()); if(getDebug()){ System.out.println("剩余线程数:"+threads.size()); } } }; //不支持多线程下载时 if (!acceptRanges) { if(getDebug()){ System.out.println("该地址不支持多线程下载"); } //定义普通下载 DownloadThread thread = new DownloadThread(url, 0, contentLength, file, false); thread.addDownloadListener(listener); thread.start(); threads.add(thread); return; } //每个请求的大小 long perThreadLength = contentLength / threadCount + 1; long startPosition = 0; long endPosition = perThreadLength; //循环创建多个下载线程 do{ if(endPosition >= contentLength) endPosition = contentLength - 1; DownloadThread thread = new DownloadThread(url, startPosition, endPosition, file); thread.addDownloadListener(listener); thread.start(); threads.add(thread); startPosition = endPosition + 1;//此处加 1,从结束位置的下一个地方开始请求 endPosition += perThreadLength; } while (startPosition < contentLength); }

     分段下载线程代码片段:

    Java代码     /**   * 现在过程代码   */  public void run() {       if(DownloadTask.getDebug()){           System.out.println("Start:" + startPosition + "-" +endPosition);       }       HttpClient httpClient = new DefaultHttpClient();       try {           HttpGet httpGet = new HttpGet(url);           if(isRange){//多线程下载               httpGet.addHeader("Range""bytes="+startPosition+"-"+endPosition);           }           HttpResponse response = httpClient.execute(httpGet);           int statusCode = response.getStatusLine().getStatusCode();           if(DownloadTask.getDebug()){               for(Header header : response.getAllHeaders()){                   System.out.println(header.getName()+":"+header.getValue());               }               System.out.println("statusCode:" + statusCode);           }           if(statusCode == 206 || (statusCode == 200 && !isRange)){               InputStream inputStream = response.getEntity().getContent();               //创建随机读写类               RandomAccessFile outputStream = new RandomAccessFile(file, "rw");               //跳到指定位置               outputStream.seek(startPosition);               int count = 0;byte[] buffer=new byte[1024];               while((count = inputStream.read(buffer, 0, buffer.length))>0){                   outputStream.write(buffer, 0, count);                   //触发下载事件                   fireAfterPerDown(new DownloadThreadEvent(this,count));               }               outputStream.close();           }           httpGet.abort();       } catch (Exception e) {           e.printStackTrace();       } finally {           //触发下载完成事件           fireDownCompleted(new DownloadThreadEvent(this, endPosition));           if(DownloadTask.getDebug()){               System.out.println("End:" + startPosition + "-" +endPosition);           }           httpClient.getConnectionManager().shutdown();       }   }   [java] view plain copy print ? /**  * 现在过程代码  */  public void run() {      if(DownloadTask.getDebug()){          System.out.println("Start:" + startPosition + "-" +endPosition);      }      HttpClient httpClient = new DefaultHttpClient();      try {          HttpGet httpGet = new HttpGet(url);          if(isRange){//多线程下载              httpGet.addHeader("Range""bytes="+startPosition+"-"+endPosition);          }          HttpResponse response = httpClient.execute(httpGet);          int statusCode = response.getStatusLine().getStatusCode();          if(DownloadTask.getDebug()){              for(Header header : response.getAllHeaders()){                  System.out.println(header.getName()+":"+header.getValue());              }              System.out.println("statusCode:" + statusCode);          }          if(statusCode == 206 || (statusCode == 200 && !isRange)){              InputStream inputStream = response.getEntity().getContent();              //创建随机读写类              RandomAccessFile outputStream = new RandomAccessFile(file, "rw");              //跳到指定位置              outputStream.seek(startPosition);              int count = 0;byte[] buffer=new byte[1024];              while((count = inputStream.read(buffer, 0, buffer.length))>0){                  outputStream.write(buffer, 0, count);                  //触发下载事件                  fireAfterPerDown(new DownloadThreadEvent(this,count));              }              outputStream.close();          }          httpGet.abort();      } catch (Exception e) {          e.printStackTrace();      } finally {          //触发下载完成事件          fireDownCompleted(new DownloadThreadEvent(this, endPosition));          if(DownloadTask.getDebug()){              System.out.println("End:" + startPosition + "-" +endPosition);          }          httpClient.getConnectionManager().shutdown();      }  }   /** * 现在过程代码 */ public void run() { if(DownloadTask.getDebug()){ System.out.println("Start:" + startPosition + "-" +endPosition); } HttpClient httpClient = new DefaultHttpClient(); try { HttpGet httpGet = new HttpGet(url); if(isRange){//多线程下载 httpGet.addHeader("Range", "bytes="+startPosition+"-"+endPosition); } HttpResponse response = httpClient.execute(httpGet); int statusCode = response.getStatusLine().getStatusCode(); if(DownloadTask.getDebug()){ for(Header header : response.getAllHeaders()){ System.out.println(header.getName()+":"+header.getValue()); } System.out.println("statusCode:" + statusCode); } if(statusCode == 206 || (statusCode == 200 && !isRange)){ InputStream inputStream = response.getEntity().getContent(); //创建随机读写类 RandomAccessFile outputStream = new RandomAccessFile(file, "rw"); //跳到指定位置 outputStream.seek(startPosition); int count = 0;byte[] buffer=new byte[1024]; while((count = inputStream.read(buffer, 0, buffer.length))>0){ outputStream.write(buffer, 0, count); //触发下载事件 fireAfterPerDown(new DownloadThreadEvent(this,count)); } outputStream.close(); } httpGet.abort(); } catch (Exception e) { e.printStackTrace(); } finally { //触发下载完成事件 fireDownCompleted(new DownloadThreadEvent(this, endPosition)); if(DownloadTask.getDebug()){ System.out.println("End:" + startPosition + "-" +endPosition); } httpClient.getConnectionManager().shutdown(); } }

     附件说明:

    1、Download.jar为编译好的可运行程序

    2、Download.zip为Eclipse项目文件

    3、运行截图  

     

    Download.jar (928.1 KB)下载次数: 44 DownLoad.zip (832.5 KB)下载次数: 70

     

    转载请注明原文地址: https://ju.6miu.com/read-964202.html

    最新回复(0)