首页 > 开发 > Java > 正文

Java编程实现服务器端支持断点续传的方法(可支持快车、迅雷)

2024-07-13 09:56:09
字体:
来源:转载
供稿:网友

这篇文章主要介绍了Java编程实现服务器端支持断点续传的方法,涉及Java文件传输的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了Java编程实现服务器端支持断点续传的方法。分享给大家供大家参考,具体如下:

大家知道Tomcat之流对静态资源可以实现断点续传支持,但是如果是一个被控制的流,如有权限控制,或下载地址仅是个代理的时候,这时候需要自己实现断点续传的支持,小弟不才,这里提供基本断点续传[a-,-b,a-b]的简单实现,经验证,可支持迅雷7和火狐的多次断点续传。现贴出代码,大家共同分享:

Servlet

 

 
  1. import java.io.BufferedOutputStream; 
  2. import java.io.File; 
  3. import java.io.IOException; 
  4. import java.io.RandomAccessFile; 
  5. import java.io.UnsupportedEncodingException; 
  6. import java.net.URI; 
  7. import java.net.URISyntaxException; 
  8. import java.net.URLDecoder; 
  9. import javax.servlet.ServletException; 
  10. import javax.servlet.ServletOutputStream; 
  11. import javax.servlet.http.HttpServletRequest; 
  12. import javax.servlet.http.HttpServletResponse; 
  13. import com.bsteel.cloud.storage.servlet.base.BaseServlet; 
  14. import com.bsteel.cloud.storage.utils.FileUtil; 
  15. /** 
  16. * 文件下载(支持断点续传【迅雷/快车/旋风/Firefox/Chrome】) 
  17. * @author jdkleo 
  18. * 
  19. */ 
  20. public class FileIoServlet extends BaseServlet { 
  21. private static final long serialVersionUID = 1L; 
  22. @Override 
  23. protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
  24. throws ServletException, IOException { 
  25. this.doPost(req, resp); 
  26. @Override 
  27. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ 
  28. download(request,response); 
  29. /** 
  30. * 文件下载 
  31. * @param request 
  32. * @param response 
  33. * @throws UnsupportedEncodingException  
  34. */ 
  35. private void download(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException { 
  36. File downloadFile = getFile(request); 
  37. long pos = FileUtil.headerSetting(downloadFile, request, response); 
  38. // log.info("跳过"+pos); 
  39. ServletOutputStream os = null;  
  40. BufferedOutputStream out = null
  41. RandomAccessFile raf = null
  42. byte b[] = new byte[1024];//暂存容器 
  43. try { 
  44. os = response.getOutputStream(); 
  45. out = new BufferedOutputStream(os); 
  46. raf = new RandomAccessFile(downloadFile, "r"); 
  47. raf.seek(pos); 
  48. try { 
  49. int n = 0; 
  50. while ((n = raf.read(b, 0, 1024)) != -1) { 
  51. out.write(b, 0, n); 
  52. out.flush(); 
  53. catch(IOException ie) { 
  54. catch (Exception e) { 
  55. log.error(e.getMessage(), e); 
  56. finally { 
  57. if (out != null) { 
  58. try { 
  59. out.close(); 
  60. catch (IOException e) { 
  61. log.error(e.getMessage(), e); 
  62. if (raf != null) { 
  63. try { 
  64. raf.close(); 
  65. catch (IOException e) { 
  66. log.error(e.getMessage(), e); 
  67. private File getFile(HttpServletRequest request) throws UnsupportedEncodingException { 
  68. String uriStr = request.getParameter("uri"); 
  69. if (null != uriStr){ 
  70. uriStr = URLDecoder.decode(uriStr,"UTF-8"); 
  71. if (uriStr.startsWith("file://")){ 
  72. uriStr = uriStr.substring(7); 
  73. return new File(uriStr); 
  74. }else if (uriStr.startsWith("hbase://")){ 
  75. try { 
  76. return new File(new URI(uriStr)); 
  77. catch (URISyntaxException e) { 
  78. log.error(e.getMessage(),e); 
  79. throw new RuntimeException("it's not a real uri"); 

Range支持

 

 
  1. import java.io.File; 
  2. import javax.servlet.http.HttpServletRequest; 
  3. import javax.servlet.http.HttpServletResponse; 
  4. /** 
  5. * 文件处理工具 
  6. * @author jdkleo 
  7. * 
  8. */ 
  9. public class FileUtil { 
  10. /** 
  11. * 断点续传支持 
  12. * @param file 
  13. * @param request 
  14. * @param response 
  15. * @return 跳过多少字节 
  16. */ 
  17. public static long headerSetting(File file,HttpServletRequest request, HttpServletResponse response) { 
  18. long len = file.length();//文件长度 
  19. if ( null == request.getHeader("Range") ){ 
  20. setResponse(new RangeSettings(len),file.getName(),response); 
  21. return 0; 
  22. String range = request.getHeader("Range").replaceAll("bytes="""); 
  23. RangeSettings settings = getSettings(len,range); 
  24. setResponse(settings,file.getName(),response); 
  25. return settings.getStart(); 
  26. private static void setResponse(RangeSettings settings,String fileName, HttpServletResponse response) { 
  27. response.addHeader("Content-Disposition""attachment; filename=/"" + IoUtil.toUtf8String(fileName) + "/""); 
  28. response.setContentType( IoUtil.setContentType(fileName));// set the MIME type. 
  29. if (!settings.isRange()) 
  30. response.addHeader("Content-Length", String.valueOf(settings.getTotalLength())); 
  31. else 
  32. long start = settings.getStart(); 
  33. long end = settings.getEnd(); 
  34. long contentLength = settings.getContentLength(); 
  35. response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT); 
  36. response.addHeader("Content-Length", String.valueOf(contentLength)); 
  37. String contentRange = new StringBuffer("bytes ").append(start).append("-").append(end).append("/").append(settings.getTotalLength()).toString(); 
  38. response.setHeader("Content-Range", contentRange); 
  39. private static RangeSettings getSettings(long len, String range) { 
  40. long contentLength = 0; 
  41. long start = 0; 
  42. long end = 0; 
  43. if (range.startsWith("-"))// -500,最后500个 
  44. contentLength = Long.parseLong(range.substring(1));//要下载的量 
  45. end = len-1; 
  46. start = len - contentLength; 
  47. else if (range.endsWith("-"))//从哪个开始 
  48. start = Long.parseLong(range.replace("-""")); 
  49. end = len -1; 
  50. contentLength = len - start; 
  51. else//从a到b 
  52. String[] se = range.split("-"); 
  53. start = Long.parseLong(se[0]); 
  54. end = Long.parseLong(se[1]); 
  55. contentLength = end-start+1; 
  56. return new RangeSettings(start,end,contentLength,len); 

Range封装

 

 
  1. public class RangeSettings{ 
  2. private long start; 
  3. private long end; 
  4. private long contentLength; 
  5. private long totalLength; 
  6. private boolean range; 
  7. public RangeSettings(){ 
  8. super(); 
  9. public RangeSettings(long start, long end, long contentLength,long totalLength) { 
  10. this.start = start; 
  11. this.end = end; 
  12. this.contentLength = contentLength; 
  13. this.totalLength = totalLength; 
  14. this.range = true
  15. public RangeSettings(long totalLength) { 
  16. this.totalLength = totalLength; 
  17. public long getStart() { 
  18. return start; 
  19. public void setStart(long start) { 
  20. this.start = start; 
  21. public long getEnd() { 
  22. return end; 
  23. public void setEnd(long end) { 
  24. this.end = end; 
  25. public long getContentLength() { 
  26. return contentLength; 
  27. public void setContentLength(long contentLength) { 
  28. this.contentLength = contentLength; 
  29. public long getTotalLength() { 
  30. return totalLength; 
  31. public void setTotalLength(long totalLength) { 
  32. this.totalLength = totalLength; 
  33. public boolean isRange() { 
  34. return range; 

IO流相关处理工具类

 

 
  1. import java.io.InputStream; 
  2. public class IoUtil { 
  3. public static String setContentType(String returnFileName){ 
  4. String contentType = "application/octet-stream"
  5. if (returnFileName.lastIndexOf(".") < 0) 
  6. return contentType; 
  7. returnFileName = returnFileName.toLowerCase(); 
  8. returnFileName = returnFileName.substring(returnFileName.lastIndexOf(".")+1); 
  9. if (returnFileName.equals("html") || returnFileName.equals("htm") || returnFileName.equals("shtml")){ 
  10. contentType = "text/html"
  11. else if (returnFileName.equals("css")){ 
  12. contentType = "text/css"
  13. else if (returnFileName.equals("xml")){ 
  14. contentType = "text/xml"
  15. else if (returnFileName.equals("gif")){ 
  16. contentType = "image/gif"
  17. else if (returnFileName.equals("jpeg") || returnFileName.equals("jpg")){ 
  18. contentType = "image/jpeg"
  19. else if (returnFileName.equals("js")){ 
  20. contentType = "application/x-javascript"
  21. else if (returnFileName.equals("atom")){ 
  22. contentType = "application/atom+xml"
  23. else if (returnFileName.equals("rss")){ 
  24. contentType = "application/rss+xml"
  25. else if (returnFileName.equals("mml")){ 
  26. contentType = "text/mathml";  
  27. else if (returnFileName.equals("txt")){ 
  28. contentType = "text/plain"
  29. else if (returnFileName.equals("jad")){ 
  30. contentType = "text/vnd.sun.j2me.app-descriptor"
  31. else if (returnFileName.equals("wml")){ 
  32. contentType = "text/vnd.wap.wml"
  33. else if (returnFileName.equals("htc")){ 
  34. contentType = "text/x-component"
  35. else if (returnFileName.equals("png")){ 
  36. contentType = "image/png"
  37. else if (returnFileName.equals("tif") || returnFileName.equals("tiff")){ 
  38. contentType = "image/tiff"
  39. else if (returnFileName.equals("wbmp")){ 
  40. contentType = "image/vnd.wap.wbmp"
  41. else if (returnFileName.equals("ico")){ 
  42. contentType = "image/x-icon"
  43. else if (returnFileName.equals("jng")){ 
  44. contentType = "image/x-jng"
  45. else if (returnFileName.equals("bmp")){ 
  46. contentType = "image/x-ms-bmp"
  47. else if (returnFileName.equals("svg")){ 
  48. contentType = "image/svg+xml"
  49. else if (returnFileName.equals("jar") || returnFileName.equals("var") || returnFileName.equals("ear")){ 
  50. contentType = "application/java-archive"
  51. else if (returnFileName.equals("doc")){ 
  52. contentType = "application/msword"
  53. else if (returnFileName.equals("pdf")){ 
  54. contentType = "application/pdf"
  55. else if (returnFileName.equals("rtf")){ 
  56. contentType = "application/rtf"
  57. else if (returnFileName.equals("xls")){ 
  58. contentType = "application/vnd.ms-excel";  
  59. else if (returnFileName.equals("ppt")){ 
  60. contentType = "application/vnd.ms-powerpoint"
  61. else if (returnFileName.equals("7z")){ 
  62. contentType = "application/x-7z-compressed"
  63. else if (returnFileName.equals("rar")){ 
  64. contentType = "application/x-rar-compressed"
  65. else if (returnFileName.equals("swf")){ 
  66. contentType = "application/x-shockwave-flash"
  67. else if (returnFileName.equals("rpm")){ 
  68. contentType = "application/x-redhat-package-manager"
  69. else if (returnFileName.equals("der") || returnFileName.equals("pem") || returnFileName.equals("crt")){ 
  70. contentType = "application/x-x509-ca-cert"
  71. else if (returnFileName.equals("xhtml")){ 
  72. contentType = "application/xhtml+xml"
  73. else if (returnFileName.equals("zip")){ 
  74. contentType = "application/zip"
  75. else if (returnFileName.equals("mid") || returnFileName.equals("midi") || returnFileName.equals("kar")){ 
  76. contentType = "audio/midi"
  77. else if (returnFileName.equals("mp3")){ 
  78. contentType = "audio/mpeg"
  79. else if (returnFileName.equals("ogg")){ 
  80. contentType = "audio/ogg"
  81. else if (returnFileName.equals("m4a")){ 
  82. contentType = "audio/x-m4a"
  83. else if (returnFileName.equals("ra")){ 
  84. contentType = "audio/x-realaudio"
  85. else if (returnFileName.equals("3gpp") || returnFileName.equals("3gp")){ 
  86. contentType = "video/3gpp"
  87. else if (returnFileName.equals("mp4") ){ 
  88. contentType = "video/mp4"
  89. else if (returnFileName.equals("mpeg") || returnFileName.equals("mpg") ){ 
  90. contentType = "video/mpeg"
  91. else if (returnFileName.equals("mov")){ 
  92. contentType = "video/quicktime"
  93. else if (returnFileName.equals("flv")){ 
  94. contentType = "video/x-flv"
  95. else if (returnFileName.equals("m4v")){ 
  96. contentType = "video/x-m4v"
  97. else if (returnFileName.equals("mng")){ 
  98. contentType = "video/x-mng"
  99. else if (returnFileName.equals("asx") || returnFileName.equals("asf")){ 
  100. contentType = "video/x-ms-asf"
  101. else if (returnFileName.equals("wmv")){ 
  102. contentType = "video/x-ms-wmv"
  103. else if (returnFileName.equals("avi")){ 
  104. contentType = "video/x-msvideo"
  105. return contentType; 
  106. // UTF8转码 
  107. public static String toUtf8String(String s) { 
  108. StringBuffer sb = new StringBuffer(); 
  109. int len = s.toCharArray().length; 
  110. for (int i = 0; i < len; i++) { 
  111. char c = s.charAt(i); 
  112. if (c >= 0 && c <= 255) { 
  113. sb.append(c); 
  114. else { 
  115. byte[] b; 
  116. try { 
  117. b = Character.toString(c).getBytes("utf-8"); 
  118. catch (Exception ex) { 
  119. System.out.println(ex); 
  120. b = new byte[0]; 
  121. for (int j = 0; j < b.length; j++) { 
  122. int k = b[j]; 
  123. if (k < 0) 
  124. k += 256; 
  125. sb.append("%" + Integer.toHexString(k).toUpperCase()); 
  126. String s_utf8 = sb.toString(); 
  127. sb.delete(0, sb.length()); 
  128. sb.setLength(0); 
  129. sb = null
  130. return s_utf8; 
  131. public static InputStream skipFully(InputStream in,long howMany)throws Exception{ 
  132. long remainning = howMany; 
  133. long len = 0; 
  134. while(remainning>0){ 
  135. len = in.skip(len); 
  136. remainning -= len; 
  137. return in

注有些类比如IoUtil方法来自于CSDN的网友总结,另外此类还不支持多Range配置如[a-b,c-d,-e]等。

希望本文所述对大家Java程序设计有所帮助。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表