1. package com.test;
2.
3. import java.io.DataInputStream;
4. import java.io.DataOutputStream;
5. import java.io.File;
6. import java.io.FileInputStream;
7. import java.io.FileOutputStream;
8. import java.io.IOException;
9. import java.io.RandomAccessFile;
10. import java.net.HttpURLConnection;
11. import java.net.URL;
12. /**
13. * 文件断点续传加分段上传线程
14. * @author wzztestin
15. *
16. */
17. /**
18. * 文件断点续传加分段上传线程
19. * @author wzztestin
20. *
21. */
22. public class DownFileFetch extends Thread {
23. null; // 文件信息 Bean
24. long[] nStartPos; // 开始位置
25. long[] nEndPos; // 结束位置
26. // 子线程对象
27. long nFileLength; // 文件长度
28. boolean bFirst = true; // 是否第一次取文件
29. boolean bStop = false; // 停止标志
30. // 文件下载的临时信息
31. // 输出到文件的输出流
32. boolean fileflag; //是本地上传还是远程下载的标志
33. //本地文件下载
34. int splitter = 0;
35.
36. /**
37. * 下载上传文件抓取初始化
38. * @param bean
39. * @throws IOException
40. */
41. public DownFileFetch(DownFileInfoBean bean) throws IOException {
42. siteInfoBean = bean;
43. /**
44. * File.separator windows是\,unix是/
45. */
46. new File(bean.getSFilePath() + File.separator
47. ".info");
48. if (tmpFile.exists()) {
49. false;
50. //读取已下载的文件信息
51. read_nPos();
52. else {
53. new long[bean.getNSplitter()];
54. new long[bean.getNSplitter()];
55. }
56. fileflag = bean.getFileflag();
57. downfile = bean.getDownfile();
58. this.splitter = bean.getNSplitter();
59. }
60.
61. public void run() {
62. // 获得文件长度
63. // 分割文件
64. // 实例 FileSplitterFetch
65. // 启动 FileSplitterFetch 线程
66. // 等待子线程返回
67. try {
68. if (bFirst) {
69. nFileLength = getFileSize();
70. if (nFileLength == -1) {
71. "File Length is not known!");
72. else if (nFileLength == -2) {
73. "File is not access!");
74. else {
75. for (int i = 0; i < nStartPos.length; i++) {
76. long) (i * (nFileLength / nStartPos.length));
77. }
78. for (int i = 0; i < nEndPos.length - 1; i++) {
79. 1];
80. }
81. 1] = nFileLength;
82. }
83. }
84. // 启动子线程
85. new DownFileSplitterFetch[nStartPos.length];
86. for (int i = 0; i < nStartPos.length; i++) {
87. new DownFileSplitterFetch(
88. siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath()
89. "_"+i,
90. nStartPos[i], nEndPos[i], i,fileflag,downfile,bFirst);
91. "Thread " + i + " , nStartPos = " + nStartPos[i]
92. ", nEndPos = " + nEndPos[i]);
93. fileSplitterFetch[i].start();
94. }
95. //下载子线程是否完成标志
96. boolean breakWhile = false;
97. while (!bStop) {
98. write_nPos();
99. 500);
100. true;
101. for (int i = 0; i < nStartPos.length; i++) {
102. if (!fileSplitterFetch[i].bDownOver) {
103. false;
104. break;
105. else{
106. write_nPos();
107. }
108. }
109. if (breakWhile){
110. break;
111. }
112. }
113. hebinfile(siteInfoBean.getSFilePath()+ File.separator + siteInfoBean.getSFileName(),splitter);
114. "文件下载结束!");
115. catch (Exception e) {
116. e.printStackTrace();
117. }
118. }
119.
120. /**
121. * 获得文件长度
122. * @return
123. */
124. public long getFileSize() {
125. int nFileLength = -1;
126. if(fileflag){
127. try {
128. new URL(siteInfoBean.getSSiteURL());
129. HttpURLConnection httpConnection = (HttpURLConnection) url
130. .openConnection();
131. "User-Agent", "NetFox");
132. int responseCode = httpConnection.getResponseCode();
133. if (responseCode >= 400) {
134. processErrorCode(responseCode);
135. //represent access is error
136. return -2;
137. }
138. String sHeader;
139. for (int i = 1;; i++) {
140. sHeader = httpConnection.getHeaderFieldKey(i);
141. if (sHeader != null) {
142. if (sHeader.equals("Content-Length")) {
143. nFileLength = Integer.parseInt(httpConnection
144. .getHeaderField(sHeader));
145. break;
146. }
147. else {
148. break;
149. }
150. }
151. catch (IOException e) {
152. e.printStackTrace();
153. catch (Exception e) {
154. e.printStackTrace();
155. }
156. DownFileUtility.log(nFileLength);
157. else{
158. try{
159. File myflie = downfile;
160. int)myflie.length();
161. catch(Exception e){
162. e.printStackTrace();
163. }
164. DownFileUtility.log(nFileLength);
165. }
166. return nFileLength;
167. }
168.
169. /**
170. * 保存下载信息(文件指针位置)
171. */
172. private void write_nPos() {
173. try {
174. new DataOutputStream(new FileOutputStream(tmpFile));
175. output.writeInt(nStartPos.length);
176. for (int i = 0; i < nStartPos.length; i++) {
177. output.writeLong(fileSplitterFetch[i].nStartPos);
178. output.writeLong(fileSplitterFetch[i].nEndPos);
179. }
180. output.close();
181. catch (IOException e) {
182. e.printStackTrace();
183. catch (Exception e) {
184. e.printStackTrace();
185. }
186. }
187.
188. /**
189. * 读取保存的下载信息(文件指针位置)
190. */
191. private void read_nPos() {
192. try {
193. new DataInputStream(new FileInputStream(
194. tmpFile));
195. int nCount = input.readInt();
196. new long[nCount];
197. new long[nCount];
198. for (int i = 0; i < nStartPos.length; i++) {
199. nStartPos[i] = input.readLong();
200. nEndPos[i] = input.readLong();
201. }
202. input.close();
203. catch (IOException e) {
204. e.printStackTrace();
205. catch (Exception e) {
206. e.printStackTrace();
207. }
208. }
209.
210. /**
211. * 输出错误信息
212. * @param nErrorCode
213. */
214. private void processErrorCode(int nErrorCode) {
215. "Error Code : " + nErrorCode);
216. }
217.
218. /**
219. * 停止文件下载
220. */
221. public void siteStop() {
222. true;
223. for (int i = 0; i < nStartPos.length; i++)
224. fileSplitterFetch[i].splitterStop();
225. }
226.
227. /**
228. * 合并文件
229. * @param sName
230. * @param splitternum
231. */
232. private void hebinfile(String sName,int splitternum){
233. try{
234. new File(sName);
235. if(file.exists()){
236. file.delete();
237. }
238. new RandomAccessFile(sName,"rw");
239. for(int i = 0;i<splitternum;i++){
240. try {
241. new RandomAccessFile (new File(sName+"_"+i),"r");
242. byte[] b = new byte[1024];
243. int nRead;
244. while ((nRead = input.read(b, 0, 1024)) > 0) {
245. 0, nRead);
246. }
247. input.close();
248. catch (Exception e) {
249. e.printStackTrace();
250. }
251. }
252. "file size is "+saveinput.length());
253. catch(Exception e){
254. e.printStackTrace();
255. }
256. }
257.
258. /**
259. * 写文件
260. * @param b
261. * @param nStart
262. * @param nLen
263. * @return
264. */
265. private int write(RandomAccessFile oSavedFile,byte[] b, int nStart, int nLen) {
266. int n = -1;
267. try {
268. oSavedFile.seek(oSavedFile.length());
269. oSavedFile.write(b, nStart, nLen);
270. n = nLen;
271. catch (IOException e) {
272. e.printStackTrace();
273. }
274. return n;
275. }
276. }
Java代码
1. package com.test;
2.
3. import java.io.File;
4. import java.io.IOException;
5. import java.io.InputStream;
6. import java.io.RandomAccessFile;
7. import java.net.HttpURLConnection;
8. import java.net.URL;
9. /**
10. * 下载上传子线程
11. * @author wzztestin
12. *
13. */
14. public class DownFileSplitterFetch extends Thread {
15. // 下载文件的地址
16. long nStartPos; // 文件分段的开始位置
17. long nEndPos; // 文件分段的结束位置
18. int nThreadID; // 线程的 ID
19. boolean bDownOver = false; // 是否下载完成
20. boolean bStop = false; // 停止下载
21. null; // 文件对象
22. boolean fileflag; //是URL下载还是本地下载
23. null;//本地下载文件
24. boolean bFirst = true;
25.
26. /**
27. * 下载,上传子线程初始化
28. * @param sURL
29. * @param sName
30. * @param nStart
31. * @param nEnd
32. * @param id
33. * @param fileflag
34. * @param downfile
35. * @throws IOException
36. */
37. public DownFileSplitterFetch(String sURL, String sName, long nStart, long nEnd,
38. int id,boolean fileflag,File downfile,boolean bFirst) throws IOException {
39. this.sURL = sURL;
40. this.nStartPos = nStart;
41. this.nEndPos = nEnd;
42. nThreadID = id;
43. new DownFileAccess(sName, nStartPos,bFirst);
44. this.fileflag = fileflag;
45. this.file = downfile;
46. this.bFirst = bFirst;
47. }
48.
49. /**
50. * 线程执行
51. */
52. public void run() {
53. if(fileflag){
54. this.urldownload();
55. else{
56. this.filedownload();
57. }
58. }
59.
60. /**
61. * 打印回应的头信息
62. * @param con
63. */
64. public void logResponseHead(HttpURLConnection con) {
65. for (int i = 1;; i++) {
66. String header = con.getHeaderFieldKey(i);
67. if (header != null){
68. " : " + con.getHeaderField(header));
69. else{
70. break;
71. }
72. }
73. }
74.
75. /**
76. * 地址下载
77. */
78. private void urldownload(){
79. "Thread " + nThreadID + " url down filesize is "+(nEndPos-nStartPos));
80. "Thread " + nThreadID + " url start >> "+nStartPos +"------end >> "+nEndPos);
81. while (nStartPos < nEndPos && !bStop) {
82. try {
83. new URL(sURL);
84. HttpURLConnection httpConnection = (HttpURLConnection) url
85. .openConnection();
86. "User-Agent", "NetFox");
87. "bytes=" + nStartPos + "-";
88. "RANGE", sProperty);
89. DownFileUtility.log(sProperty);
90. InputStream input = httpConnection.getInputStream();
91. byte[] b = new byte[1024];
92. int nRead;
93. while ((nRead = input.read(b, 0, 1024)) > 0
94. && nStartPos < nEndPos && !bStop) {
95. if((nStartPos+nRead)>nEndPos)
96. {
97. int)(nEndPos - nStartPos);
98. }
99. 0, nRead);
100. }
101. "Thread " + nThreadID + " nStartPos : "+nStartPos);
102. fileAccessI.oSavedFile.close();
103. "Thread " + nThreadID + " is over!");
104. input.close();
105. true;
106. catch (Exception e) {
107. e.printStackTrace();
108. }
109. }
110. if(!bDownOver){
111. if(nStartPos >= nEndPos){
112. true;
113. }
114. }
115. }
116.
117. /**
118. * 文件下载
119. */
120. private void filedownload(){
121. "Thread " + nThreadID + " down filesize is "+(nEndPos-nStartPos));
122. "Thread " + nThreadID + " start >> "+nStartPos +"------end >> "+nEndPos);
123. while (nStartPos < nEndPos && !bStop) {
124. try {
125. new RandomAccessFile(file,"r");
126. input.seek(nStartPos);
127. byte[] b = new byte[1024];
128. int nRead;
129. while ((nRead = input.read(b, 0, 1024)) > 0
130. && nStartPos < nEndPos && !bStop) {
131. if((nStartPos+nRead)>nEndPos)
132. {
133. int)(nEndPos - nStartPos);
134. }
135. 0, nRead);
136. }
137. fileAccessI.oSavedFile.close();
138. "Thread " + nThreadID + " is over!");
139. input.close();
140. true;
141. input.close();
142. catch (Exception e) {
143. e.printStackTrace();
144. }
145. }
146. if(!bDownOver){
147. if(nStartPos >= nEndPos){
148. true;
149. }
150. }
151. "Thread " + nThreadID + "last start >> "+nStartPos );
152. }
153.
154. /**
155. * 停止
156. */
157. public void splitterStop() {
158. true;
159. }
160. }
Java代码
1. package com.test;
2.
3. import java.io.*;
4.
5. /**
6. * 文件对象
7. * @author wzztestin
8. *
9. */
10. public class DownFileAccess implements Serializable {
11. /**
12. *
13. */
14. private static final long serialVersionUID = -2518013155676212866L;
15. //写入文件的流
16. RandomAccessFile oSavedFile;
17. //开始位置
18. long nPos;
19. boolean bFirst;
20.
21. public DownFileAccess() throws IOException {
22. this("", 0,true);
23. }
24.
25. /**
26. * 写入文件初始化
27. * @param sName
28. * @param nPos
29. * @throws IOException
30. */
31. public DownFileAccess(String sName, long nPos,boolean bFirst) throws IOException {
32. new File(sName);
33. new RandomAccessFile(wfile,"rw");
34. if(!bFirst){
35. oSavedFile.seek(wfile.length());
36. }
37. this.nPos = nPos;
38. this.bFirst = bFirst;
39. }
40.
41. /**
42. * 写文件
43. * @param b
44. * @param nStart
45. * @param nLen
46. * @return
47. */
48. public synchronized int write(byte[] b, int nStart, int nLen) {
49. int n = -1;
50. try {
51. oSavedFile.write(b, nStart, nLen);
52. n = nLen;
53. catch (IOException e) {
54. e.printStackTrace();
55. }
56. return n;
57. }
58. }
Java代码
1. package com.test;
2.
3. import java.io.File;
4.
5. public class DownFileInfoBean {
6. private String sSiteURL; // 文件的下载地址
7. private String sFilePath; // 保存文件的路径
8. private String sFileName; // 保存文件的名字
9. private int nSplitter; // 文件分成几段,默认是5段
10. private boolean fileflag; // 如果为FALSE则是本地下载,为TRUE则URL下载
11. private File downfile;
12.
13. public File getDownfile() {
14. return downfile;
15. }
16.
17. public void setDownfile(File downfile) {
18. this.downfile = downfile;
19. }
20.
21. public boolean getFileflag() {
22. return fileflag;
23. }
24.
25. public void setFileflag(boolean fileflag) {
26. this.fileflag = fileflag;
27. }
28.
29. /**
30. * 默认初始化
31. */
32. public DownFileInfoBean() {
33. // default 5
34. this("", "", "", 5,false,null);
35. }
36.
37. /**
38. * 下载文件信息初始化
39. * @param sURL 下载的链接地址
40. * @param sPath 上传的保存路径
41. * @param sName 上传保存的文件名
42. * @param nSpiltter 文件分段个数
43. * @param fileflag 是本地文件上传下载还是链接上传下载的标志
44. * @param downfile 本地下载文件(FILE)
45. */
46. public DownFileInfoBean(String sURL, String sPath, String sName, int nSpiltter,boolean fileflag,File downfile) {
47. sSiteURL = sURL;
48. sFilePath = sPath;
49. sFileName = sName;
50. this.nSplitter = nSpiltter;
51. this.fileflag = fileflag;
52. this.downfile = downfile;
53. }
54.
55. public String getSSiteURL() {
56. return sSiteURL;
57. }
58.
59. public void setSSiteURL(String value) {
60. sSiteURL = value;
61. }
62.
63. public String getSFilePath() {
64. return sFilePath;
65. }
66.
67. public void setSFilePath(String value) {
68. sFilePath = value;
69. }
70.
71. public String getSFileName() {
72. return sFileName;
73. }
74.
75. public void setSFileName(String value) {
76. sFileName = value;
77. }
78.
79. public int getNSplitter() {
80. return nSplitter;
81. }
82.
83. public void setNSplitter(int nCount) {
84. nSplitter = nCount;
85. }
86. }
Java代码
1. package com.test;
2.
3. /**
4. * 简单的工具类
5. * @author wzztestin
6. *
7. */
8. public class DownFileUtility {
9. public DownFileUtility() {
10. }
11.
12. /**
13. * 休眠时长
14. * @param nSecond
15. */
16. public static void sleep(int nSecond) {
17. try {
18. Thread.sleep(nSecond);
19. catch (Exception e) {
20. e.printStackTrace();
21. }
22. }
23.
24. /**
25. * 打印日志信息
26. * @param sMsg
27. */
28. public static void log(String sMsg) {
29. System.err.println(sMsg);
30. }
31.
32. /**
33. * 打印日志信息
34. * @param sMsg
35. */
36. public static void log(int sMsg) {
37. System.err.println(sMsg);
38. }
39. }
Java代码
1. package com.test;
2.
3. public class TestMethod {
4. public TestMethod() {
5. try {
6. new DownFileInfoBean(
7. "http://cdn.market.hiapk.com/data/upload//2012/09_27/17/car.wu.wei.kyo.shandian_174928.apk", "D:\\temp",
8. "shandian_174928.apk", 5,true,null);
9. /*File file = new File("D:\\dan07.apk");
10. DownFileInfoBean bean = new DownFileInfoBean(null, "D:\\temp",
11. "dan07.apk", 3,false,file);*/
12. new DownFileFetch(bean);
13. fileFetch.start();
14. catch (Exception e) {
15. e.printStackTrace();
16. }
17. }
18.
19. public static void main(String[] args) {
20. new TestMethod();
21. }
22. }