本文實例講述了Java編程實現服務器端支持斷點續傳的方法。分享給大家供大家參考,具體如下:
大家知道Tomcat之流對靜態資源可以實現斷點續傳支持,但是如果是一個被控制的流,如有權限控制,或下載地址僅是個代理的時候,這時候需要自己實現斷點續傳的支持,小弟不才,這里提供基本斷點續傳[a-,-b,a-b]的簡單實現,經驗證,可支持迅雷7和火狐的多次斷點續傳。現貼出代碼,大家共同分享:
Servlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.bsteel.cloud.storage.servlet.base.BaseServlet; import com.bsteel.cloud.storage.utils.FileUtil; /** * 文件下載(支持斷點續傳【迅雷\快車\旋風\Firefox\Chrome】) * @author jdkleo * */ public class FileIoServlet extends BaseServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this .doPost(req, resp); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ download(request,response); } /** * 文件下載 * @param request * @param response * @throws UnsupportedEncodingException */ private void download(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException { File downloadFile = getFile(request); long pos = FileUtil.headerSetting(downloadFile, request, response); // log.info("跳過"+pos); ServletOutputStream os = null ; BufferedOutputStream out = null ; RandomAccessFile raf = null ; byte b[] = new byte [ 1024 ]; //暫存容器 try { os = response.getOutputStream(); out = new BufferedOutputStream(os); raf = new RandomAccessFile(downloadFile, "r" ); raf.seek(pos); try { int n = 0 ; while ((n = raf.read(b, 0 , 1024 )) != - 1 ) { out.write(b, 0 , n); } out.flush(); } catch (IOException ie) { } } catch (Exception e) { log.error(e.getMessage(), e); } finally { if (out != null ) { try { out.close(); } catch (IOException e) { log.error(e.getMessage(), e); } } if (raf != null ) { try { raf.close(); } catch (IOException e) { log.error(e.getMessage(), e); } } } } private File getFile(HttpServletRequest request) throws UnsupportedEncodingException { String uriStr = request.getParameter( "uri" ); if ( null != uriStr){ uriStr = URLDecoder.decode(uriStr, "UTF-8" ); if (uriStr.startsWith( "file://" )){ uriStr = uriStr.substring( 7 ); return new File(uriStr); } else if (uriStr.startsWith( "hbase://" )){ try { return new File( new URI(uriStr)); } catch (URISyntaxException e) { log.error(e.getMessage(),e); } } } throw new RuntimeException( "it's not a real uri" ); } } |
Range支持
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
import java.io.File; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 文件處理工具 * @author jdkleo * */ public class FileUtil { /** * 斷點續傳支持 * @param file * @param request * @param response * @return 跳過多少字節 */ public static long headerSetting(File file,HttpServletRequest request, HttpServletResponse response) { long len = file.length(); //文件長度 if ( null == request.getHeader( "Range" ) ){ setResponse( new RangeSettings(len),file.getName(),response); return 0 ; } String range = request.getHeader( "Range" ).replaceAll( "bytes=" , "" ); RangeSettings settings = getSettings(len,range); setResponse(settings,file.getName(),response); return settings.getStart(); } private static void setResponse(RangeSettings settings,String fileName, HttpServletResponse response) { response.addHeader( "Content-Disposition" , "attachment; filename=\"" + IoUtil.toUtf8String(fileName) + "\"" ); response.setContentType( IoUtil.setContentType(fileName)); // set the MIME type. if (!settings.isRange()) { response.addHeader( "Content-Length" , String.valueOf(settings.getTotalLength())); } else { long start = settings.getStart(); long end = settings.getEnd(); long contentLength = settings.getContentLength(); response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT); response.addHeader( "Content-Length" , String.valueOf(contentLength)); String contentRange = new StringBuffer( "bytes " ).append(start).append( "-" ).append(end).append( "/" ).append(settings.getTotalLength()).toString(); response.setHeader( "Content-Range" , contentRange); } } private static RangeSettings getSettings( long len, String range) { long contentLength = 0 ; long start = 0 ; long end = 0 ; if (range.startsWith( "-" )) // -500,最后500個 { contentLength = Long.parseLong(range.substring( 1 )); //要下載的量 end = len- 1 ; start = len - contentLength; } else if (range.endsWith( "-" )) //從哪個開始 { start = Long.parseLong(range.replace( "-" , "" )); end = len - 1 ; contentLength = len - start; } else //從a到b { String[] se = range.split( "-" ); start = Long.parseLong(se[ 0 ]); end = Long.parseLong(se[ 1 ]); contentLength = end-start+ 1 ; } return new RangeSettings(start,end,contentLength,len); } } |
Range封裝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public class RangeSettings{ private long start; private long end; private long contentLength; private long totalLength; private boolean range; public RangeSettings(){ super (); } public RangeSettings( long start, long end, long contentLength, long totalLength) { this .start = start; this .end = end; this .contentLength = contentLength; this .totalLength = totalLength; this .range = true ; } public RangeSettings( long totalLength) { this .totalLength = totalLength; } public long getStart() { return start; } public void setStart( long start) { this .start = start; } public long getEnd() { return end; } public void setEnd( long end) { this .end = end; } public long getContentLength() { return contentLength; } public void setContentLength( long contentLength) { this .contentLength = contentLength; } public long getTotalLength() { return totalLength; } public void setTotalLength( long totalLength) { this .totalLength = totalLength; } public boolean isRange() { return range; } } |
IO流相關處理工具類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
import java.io.InputStream; public class IoUtil { public static String setContentType(String returnFileName){ String contentType = "application/octet-stream" ; if (returnFileName.lastIndexOf( "." ) < 0 ) return contentType; returnFileName = returnFileName.toLowerCase(); returnFileName = returnFileName.substring(returnFileName.lastIndexOf( "." )+ 1 ); if (returnFileName.equals( "html" ) || returnFileName.equals( "htm" ) || returnFileName.equals( "shtml" )){ contentType = "text/html" ; } else if (returnFileName.equals( "css" )){ contentType = "text/css" ; } else if (returnFileName.equals( "xml" )){ contentType = "text/xml" ; } else if (returnFileName.equals( "gif" )){ contentType = "image/gif" ; } else if (returnFileName.equals( "jpeg" ) || returnFileName.equals( "jpg" )){ contentType = "image/jpeg" ; } else if (returnFileName.equals( "js" )){ contentType = "application/x-javascript" ; } else if (returnFileName.equals( "atom" )){ contentType = "application/atom+xml" ; } else if (returnFileName.equals( "rss" )){ contentType = "application/rss+xml" ; } else if (returnFileName.equals( "mml" )){ contentType = "text/mathml" ; } else if (returnFileName.equals( "txt" )){ contentType = "text/plain" ; } else if (returnFileName.equals( "jad" )){ contentType = "text/vnd.sun.j2me.app-descriptor" ; } else if (returnFileName.equals( "wml" )){ contentType = "text/vnd.wap.wml" ; } else if (returnFileName.equals( "htc" )){ contentType = "text/x-component" ; } else if (returnFileName.equals( "png" )){ contentType = "image/png" ; } else if (returnFileName.equals( "tif" ) || returnFileName.equals( "tiff" )){ contentType = "image/tiff" ; } else if (returnFileName.equals( "wbmp" )){ contentType = "image/vnd.wap.wbmp" ; } else if (returnFileName.equals( "ico" )){ contentType = "image/x-icon" ; } else if (returnFileName.equals( "jng" )){ contentType = "image/x-jng" ; } else if (returnFileName.equals( "bmp" )){ contentType = "image/x-ms-bmp" ; } else if (returnFileName.equals( "svg" )){ contentType = "image/svg+xml" ; } else if (returnFileName.equals( "jar" ) || returnFileName.equals( "var" ) || returnFileName.equals( "ear" )){ contentType = "application/java-archive" ; } else if (returnFileName.equals( "doc" )){ contentType = "application/msword" ; } else if (returnFileName.equals( "pdf" )){ contentType = "application/pdf" ; } else if (returnFileName.equals( "rtf" )){ contentType = "application/rtf" ; } else if (returnFileName.equals( "xls" )){ contentType = "application/vnd.ms-excel" ; } else if (returnFileName.equals( "ppt" )){ contentType = "application/vnd.ms-powerpoint" ; } else if (returnFileName.equals( "7z" )){ contentType = "application/x-7z-compressed" ; } else if (returnFileName.equals( "rar" )){ contentType = "application/x-rar-compressed" ; } else if (returnFileName.equals( "swf" )){ contentType = "application/x-shockwave-flash" ; } else if (returnFileName.equals( "rpm" )){ contentType = "application/x-redhat-package-manager" ; } else if (returnFileName.equals( "der" ) || returnFileName.equals( "pem" ) || returnFileName.equals( "crt" )){ contentType = "application/x-x509-ca-cert" ; } else if (returnFileName.equals( "xhtml" )){ contentType = "application/xhtml+xml" ; } else if (returnFileName.equals( "zip" )){ contentType = "application/zip" ; } else if (returnFileName.equals( "mid" ) || returnFileName.equals( "midi" ) || returnFileName.equals( "kar" )){ contentType = "audio/midi" ; } else if (returnFileName.equals( "mp3" )){ contentType = "audio/mpeg" ; } else if (returnFileName.equals( "ogg" )){ contentType = "audio/ogg" ; } else if (returnFileName.equals( "m4a" )){ contentType = "audio/x-m4a" ; } else if (returnFileName.equals( "ra" )){ contentType = "audio/x-realaudio" ; } else if (returnFileName.equals( "3gpp" ) || returnFileName.equals( "3gp" )){ contentType = "video/3gpp" ; } else if (returnFileName.equals( "mp4" ) ){ contentType = "video/mp4" ; } else if (returnFileName.equals( "mpeg" ) || returnFileName.equals( "mpg" ) ){ contentType = "video/mpeg" ; } else if (returnFileName.equals( "mov" )){ contentType = "video/quicktime" ; } else if (returnFileName.equals( "flv" )){ contentType = "video/x-flv" ; } else if (returnFileName.equals( "m4v" )){ contentType = "video/x-m4v" ; } else if (returnFileName.equals( "mng" )){ contentType = "video/x-mng" ; } else if (returnFileName.equals( "asx" ) || returnFileName.equals( "asf" )){ contentType = "video/x-ms-asf" ; } else if (returnFileName.equals( "wmv" )){ contentType = "video/x-ms-wmv" ; } else if (returnFileName.equals( "avi" )){ contentType = "video/x-msvideo" ; } return contentType; } // UTF8轉碼 public static String toUtf8String(String s) { StringBuffer sb = new StringBuffer(); int len = s.toCharArray().length; for ( int i = 0 ; i < len; i++) { char c = s.charAt(i); if (c >= 0 && c <= 255 ) { sb.append(c); } else { byte [] b; try { b = Character.toString(c).getBytes( "utf-8" ); } catch (Exception ex) { System.out.println(ex); b = new byte [ 0 ]; } for ( int j = 0 ; j < b.length; j++) { int k = b[j]; if (k < 0 ) k += 256 ; sb.append( "%" + Integer.toHexString(k).toUpperCase()); } } } String s_utf8 = sb.toString(); sb.delete( 0 , sb.length()); sb.setLength( 0 ); sb = null ; return s_utf8; } public static InputStream skipFully(InputStream in, long howMany) throws Exception{ long remainning = howMany; long len = 0 ; while (remainning> 0 ){ len = in.skip(len); remainning -= len; } return in; } } |
注有些類比如IoUtil方法來自于CSDN的網友總結,另外此類還不支持多Range配置如[a-b,c-d,-e]等。
希望本文所述對大家Java程序設計有所幫助。