java实现文件断点续传下载功能

前端技术 2023/09/08 Java

本文实例为大家分享了java断点续传下载的代码,供大家参考,具体内容如下

1. Java代码    

//实现文件下载功能
  public String downloadFile(){
    File dir = new File(filepath);//获取文件路劲
    if(!dir.exists()) {
      System.out.println(\"文件路径错误\");
      log.debug(\"文件路径错误\");
      return \"failed\";// 判断文件或文件夹是否存在
    }
     File downloadFile = new File(dir, filename);//在指定目录下查找文件
     if(!downloadFile.isFile()){
       System.out.println(\"文件不存在\");
        log.debug(\"文件不存在\");
        return \"failed\";// 判断文件或文件夹是否存在
     }
     try {
      downloadFileRanges(downloadFile);
     } catch(ClientAbortException e){
       System.out.println(\"连接被终止\");
       log.debug(\"连接被终止\");
     } catch (IOException e) {
      e.printStackTrace();
     }
    return null;
   }
   
  private void downloadFileRanges(File downloadFile) throws IOException {
     // 要下载的文件大小
     long fileLength = downloadFile.length();
     // 已下载的文件大小
     long pastLength = 0;
     // 是否快车下载,否则为迅雷或其他
     boolean isFlashGet = true;
     // 用于记录需要下载的结束字节数(迅雷或其他下载)
     long lenEnd = 0;
     // 用于记录客户端要求下载的数据范围字串
     String rangeBytes = request.getHeader(\"Range\");
     //用于随机读取写入文件
     RandomAccessFile raf = null;
     OutputStream os = null;
     OutputStream outPut = null;
     byte b[] = new byte[1024];
     // 如果客户端下载请求中包含了范围
     if (null != rangeBytes) 
     {
      // 返回码 206
      response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
      rangeBytes = request.getHeader(\"Range\").replaceAll(\"bytes=\", \"\");
      // 判断 Range 字串模式
      if (rangeBytes.indexOf(\'-\') == rangeBytes.length() - 1) 
      {
      // 无结束字节数,为快车
      isFlashGet = true;
      rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf(\'-\'));
      pastLength = Long.parseLong(rangeBytes.trim());
      } 
      else
      {
      // 迅雷下载
      isFlashGet = false;
      String startBytes = rangeBytes.substring(0,
       rangeBytes.indexOf(\'-\'));
      String endBytes = rangeBytes.substring(
       rangeBytes.indexOf(\'-\') + 1, rangeBytes.length());
      // 已下载文件段
      pastLength = Long.parseLong(startBytes.trim());
      // 还需下载的文件字节数(从已下载文件段开始)
      lenEnd = Long.parseLong(endBytes);
      }
     }
     // 通知客户端允许断点续传,响应格式为:Accept-Ranges: bytes
     response.setHeader(\"Accept-Ranges\", \"bytes\");
     // response.reset();
     // 如果为第一次下载,则状态默认为 200,响应格式为: HTTP/1.1 200 ok
     if (0 != pastLength)
     {
      // 内容范围字串
      String contentRange = \"\";
      // 响应格式
      // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]||[文件的总大小]
      if (isFlashGet)
      {
      contentRange = new StringBuffer(\"bytes\")
       .append(new Long(pastLength).toString()).append(\"-\")
       .append(new Long(fileLength - 1).toString())
       .append(\"/\").append(new Long(fileLength).toString())
       .toString();
      }
      else
      {
      contentRange = new StringBuffer(rangeBytes).append(\"/\")
       .append(new Long(fileLength).toString()).toString();
      }
      response.setHeader(\"Content-Range\", contentRange);
     }
     String fileName = getDownloadChineseFileName(filename);
     response.setHeader(\"Content-Disposition\",
      \"attachment;filename=\" + fileName + \"\");
     // 响应的格式是:
     response.setContentType(\"application/octet-stream\");
     response.addHeader(\"Content-Length\", String.valueOf(fileLength));
     try
     {
      os = response.getOutputStream();
      outPut = new BufferedOutputStream(os);
      raf = new RandomAccessFile(downloadFile, \"r\");
      // 跳过已下载字节
      raf.seek(pastLength);
      if (isFlashGet) 
      {
      // 快车等
      int n = 0;
      while ((n = raf.read(b, 0, 1024)) != -1) 
      {
       outPut.write(b, 0, n);
      }
      } 
      else
      {
      // 迅雷等
      while (raf.getFilePointer() < lenEnd)
      {
       outPut.write(raf.read());
      }
      }
      outPut.flush();
     }
     catch (IOException e)
     {
      /**
      * 在写数据的时候 对于 ClientAbortException 之类的异常
      * 是因为客户端取消了下载,而服务器端继续向浏览器写入数据时, 抛出这个异常,这个是正常的。 尤其是对于迅雷这种吸血的客户端软件。
      * 明明已经有一个线程在读取 bytes=1275856879-1275877358,
      * 如果短时间内没有读取完毕,迅雷会再启第二个、第三个。。。线程来读取相同的字节段, 直到有一个线程读取完毕,迅雷会 KILL
      * 掉其他正在下载同一字节段的线程, 强行中止字节读出,造成服务器抛 ClientAbortException。
      * 所以,我们忽略这种异常
      */
     } 
     finally
     {
      if(outPut != null)
      { 
      outPut.close();
      }
      if(raf != null)
      {
      raf.close();
      }
     }
     }
   
   
   
  private String getDownloadChineseFileName(String paramName) 
   {
   String downloadChineseFileName = \"\";
   try
   {
    downloadChineseFileName = new String(paramName.getBytes(\"GBK\"),
     \"ISO8859-1\");
   }
   catch (UnsupportedEncodingException e)
   {
    e.printStackTrace();
   }
   return downloadChineseFileName;
   }
   
   
   
  public String getFilepath() {
    return filepath;
  }
  public void setFilepath(String filepath) {
    this.filepath = filepath;
  }
  public String getFilename() {
    return filename;
  }
  public void setFilename(String filename) {
    this.filename = filename;
  }
  public HttpServletRequest getRequest() {
   return request;
   }
   public HttpServletResponse getResponse() {
   return response;
   }

2. struts部分    

复制代码 代码如下:
<action name=\"downloadFile\" class=\"downloadFileAction\" method=\"downloadFile\">
   <result name=\"failed\" type=\"redirectAction\">showDownloadFileNameList</result>
</action>

3. jsp部分    

复制代码 代码如下:
<td><a href=\"downloadFile?filename=${fileMap.key }&&filepath=${fileMap.value }\">文件下载</a></td>

本文地址:https://www.stayed.cn/item/21629

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。