java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java断点续传下载

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

作者:钟志诚

这篇文章主要为大家详细介绍了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>

您可能感兴趣的文章:
阅读全文