仓酷云

标题: 发布一篇HTTP多线程断点续传下载的实验 [打印本页]

作者: 再见西城    时间: 2015-1-18 11:25
标题: 发布一篇HTTP多线程断点续传下载的实验
首先java功能强大的背后是其复杂性,就拿web来说,当今流行的框架有很多,什么struts,spring,jQuery等等,而这无疑增加了java的复杂性。
间接看代码吧,空话一点未几说。
功效先容:
1多线程HTTP下载
2撑持断点续传
3一时文件下载,乐成后更名
4供应防盗链的破解
Java代码
  1. 1.importjava.io.BufferedInputStream;
  2. 2.importjava.io.BufferedWriter;
  3. 3.importjava.io.File;
  4. 4.importjava.io.OutputStreamWriter;
  5. 5.importjava.io.RandomAccessFile;
  6. 6.importjava.net.Socket;
  7. 7.importjava.net.URL;
  8. 8.importjava.net.URLConnection;
  9. 9.importjava.util.HashMap;
  10. 10.importjava.util.Map;
  11. 11.
  12. 12./**
  13. 13.*HTTP的多线程下载工具。
  14. 14.*
  15. 15.*@author赵学庆www.java2000.net
  16. 16.*/
  17. 17.publicclassHTTPDownloaderextendsThread{
  18. 18.//要下载的页面
  19. 19.privateStringpage;
  20. 20.
  21. 21.//保留的路径
  22. 22.privateStringsavePath;
  23. 23.
  24. 24.//线程数
  25. 25.privateintthreadNumber=2;
  26. 26.
  27. 27.//来历地点
  28. 28.privateStringreferer;
  29. 29.
  30. 30.privateStringcookie;
  31. 31.
  32. 32.intthreadPointer=0;
  33. 33.
  34. 34.privateMap<Integer,HTTPDownloaderThread>threadPool=newHashMap<Integer,HTTPDownloaderThread>();//线程迟
  35. 35.
  36. 36.//最小的块尺寸。假如文件尺寸除以线程数小于这个,则会削减线程数。37.privateintMIN_BLOCK=10*1024;
  37. 38.
  38. 39.publicstaticvoidmain(String[]args)throwsException{
  39. 40.HTTPDownloaderd=newHTTPDownloader("http://www.xxxxx.com/a.rar",null,"d://a.rar",10,null);
  40. 41.d.down();
  41. 42.}
  42. 43.
  43. 44.publicvoidrun(){
  44. 45.try{
  45. 46.down();
  46. 47.}catch(Exceptione){
  47. 48.e.printStackTrace();
  48. 49.}
  49. 50.}
  50. 51.
  51. 52./**
  52. 53.*下载操纵
  53. 54.*
  54. 55.*@throwsException
  55. 56.*/
  56. 57.publicvoiddown()throwsException{
  57. 58.URLurl=newURL(page);//创立URL
  58. 59.URLConnectioncon=url.openConnection();//创建毗连
  59. 60.con.setRequestProperty("Referer",referer==null?page:referer);
  60. 61.con.setRequestProperty("UserAgent","Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;flashget)");
  61. 62.intcontentLen=con.getContentLength();//取得资本长度
  62. 63.if((contentLen/MIN_BLOCK+1)<threadNumber){
  63. 64.threadNumber=contentLen/MIN_BLOCK+1;//调剂下载线程数65.}
  64. 66.if(threadNumber>10){
  65. 67.threadNumber=10;
  66. 68.}
  67. 69.intbegin=0;
  68. 70.intstep=contentLen/threadNumber+1;
  69. 71.intend=0;
  70. 72.HTTPDownloaderThreadthread;
  71. 73.for(threadPointer=0;threadPointer<threadNumber;threadPointer++){
  72. 74.end+=step;
  73. 75.if(end>contentLen){
  74. 76.end=contentLen;
  75. 77.}
  76. 78.thread=newHTTPDownloaderThread(this,threadPointer,begin,end);
  77. 79.threadPool.put(threadPointer,thread);
  78. 80.thread.start();
  79. 81.begin=end;
  80. 82.}
  81. 83.}
  82. 84.
  83. 85./**
  84. 86.*一个线程完活了。
  85. 87.*
  86. 88.*@paramid完活的线程id
  87. 89.*/
  88. 90.publicsynchronizedvoidfinished(intid){
  89. 91.threadNumber--;
  90. 92.threadPool.remove(id);
  91. 93.if(threadNumber<=0){
  92. 94.System.out.println("FINISHED:"+savePath);
  93. 95.Filef1=newFile(savePath+".tmp");
  94. 96.Filef2=newFile(savePath);
  95. 97.//假如方针文件已存在,则实验删除它
  96. 98.//最多实验3次,距离1秒钟。
  97. 99.inttimes=3;
  98. 100.while(f2.exists()&&times>0){
  99. 101.if(f2.delete()){
  100. 102.break;
  101. 103.}
  102. 104.try{
  103. 105.Thread.sleep(1000);
  104. 106.}catch(InterruptedExceptione){
  105. 107.e.printStackTrace();
  106. 108.}
  107. 109.times--;
  108. 110.}
  109. 111.if(!f2.exists()){
  110. 112.if(!f1.renameTo(f2)){
  111. 113.System.out.println("更名失利!");
  112. 114.}
  113. 115.}else{
  114. 116.System.out.println("方针文件存在,且没法删除,没法更名");
  115. 117.}
  116. 118.}else{
  117. 119.intsize=0;
  118. 120.HTTPDownloaderThreado=null;
  119. 121.//实验查找一个能够分管的线程
  120. 122.for(HTTPDownloaderThreadthread:threadPool.values()){
  121. 123.if(thread.endPos-thread.curPos>size){
  122. 124.size=thread.endPos-thread.curPos;
  123. 125.o=thread;
  124. 126.}
  125. 127.}
  126. 128.if(size>MIN_BLOCK*2){
  127. 129.if(o.isAlive()){
  128. 130.intendPos=o.endPos;
  129. 131.intbeginPos=o.endPos-((o.endPos-o.curPos)/2);
  130. 132.o.endPos=beginPos;
  131. 133.threadNumber++;
  132. 134.threadPointer++;
  133. 135.HTTPDownloaderThreadthread=newHTTPDownloaderThread(this,threadPointer,beginPos,endPos);
  134. 136.threadPool.put(threadPointer,thread);
  135. 137.System.out.println("AHelpThreadfor"+o.id+"isstartedwith:"+threadPointer);
  136. 138.thread.start();
  137. 139.}
  138. 140.}
  139. 141.}
  140. 142.}
  141. 143.
  142. 144.publicHTTPDownloader(){
  143. 145.}
  144. 146.
  145. 147./**
  146. 148.*下载
  147. 149.*
  148. 150.*@parampage被下载的页面
  149. 151.*@paramsavePath保留的路径
  150. 152.*/
  151. 153.publicHTTPDownloader(Stringpage,StringsavePath){
  152. 154.this(page,savePath,10);
  153. 155.}
  154. 156.
  155. 157./**
  156. 158.*下载
  157. 159.*
  158. 160.*@parampage被下载的页面
  159. 161.*@paramsavePath保留的路径
  160. 162.*@paramthreadNumber线程数
  161. 163.*/
  162. 164.publicHTTPDownloader(Stringpage,StringsavePath,intthreadNumber){
  163. 165.this(page,page,savePath,10,null);
  164. 166.}
  165. 167.
  166. 168./**
  167. 169.*下载
  168. 170.*
  169. 171.*@parampage被下载的页面
  170. 172.*@paramsavePath保留的路径
  171. 173.*@paramthreadNumber线程数
  172. 174.*@paramreferer来历
  173. 175.*/
  174. 176.publicHTTPDownloader(Stringpage,Stringreferer,StringsavePath,intthreadNumber,Stringcookie){
  175. 177.this.page=page;
  176. 178.this.savePath=savePath;
  177. 179.this.threadNumber=threadNumber;
  178. 180.this.referer=referer;
  179. 181.}
  180. 182.
  181. 183.publicStringgetPage(){
  182. 184.returnpage;
  183. 185.}
  184. 186.
  185. 187.publicvoidsetPage(Stringpage){
  186. 188.this.page=page;
  187. 189.}
  188. 190.
  189. 191.publicStringgetSavePath(){
  190. 192.returnsavePath;
  191. 193.}
  192. 194.
  193. 195.publicvoidsetSavePath(StringsavePath){
  194. 196.this.savePath=savePath;
  195. 197.}
  196. 198.
  197. 199.publicintgetThreadNumber(){
  198. 200.returnthreadNumber;
  199. 201.}
  200. 202.
  201. 203.publicvoidsetThreadNumber(intthreadNumber){
  202. 204.this.threadNumber=threadNumber;
  203. 205.}
  204. 206.
  205. 207.publicStringgetReferer(){
  206. 208.returnreferer;
  207. 209.}
  208. 210.
  209. 211.publicvoidsetReferer(Stringreferer){
  210. 212.this.referer=referer;
  211. 213.}
  212. 214.
  213. 215.publicStringgetCookie(){
  214. 216.returncookie;
  215. 217.}
  216. 218.
  217. 219.publicvoidsetCookie(Stringcookie){
  218. 220.this.cookie=cookie;
  219. 221.}
  220. 222.}
  221. 223.
  222. 224./**
  223. 225.*下载线程
  224. 226.*
  225. 227.*@author赵学庆www.java2000.net
  226. 228.*/
  227. 229.classHTTPDownloaderThreadextendsThread{
  228. 230.HTTPDownloadermanager;
  229. 231.
  230. 232.intstartPos;
  231. 233.
  232. 234.intendPos;
  233. 235.
  234. 236.intid;
  235. 237.
  236. 238.intcurPos;
  237. 239.
  238. 240.intBUFFER_SIZE=40960;
  239. 241.
  240. 242.intreadByte=0;
  241. 243.
  242. 244.HTTPDownloaderThread(HTTPDownloadermanager,intid,intstartPos,intendPos){
  243. 245.this.id=id;
  244. 246.this.manager=manager;
  245. 247.this.startPos=startPos;
  246. 248.this.endPos=endPos;
  247. 249.}
  248. 250.
  249. 251.publicvoidrun(){
  250. 252.System.out.println("线程"+id+"启动,"+startPos+"-"+endPos);
  251. 253.//创立一个buff
  252. 254.BufferedInputStreambis=null;
  253. 255.RandomAccessFilefos=null;
  254. 256.//缓冲区巨细
  255. 257.byte[]buf=newbyte[BUFFER_SIZE];
  256. 258.booleantimeout=false;
  257. 259.Socketsocket=null;
  258. 260.try{
  259. 261.curPos=startPos;
  260. 262.Filefile=newFile(manager.getSavePath()+".tmp");
  261. 263.//创立RandomAccessFile
  262. 264.fos=newRandomAccessFile(file,"rw");
  263. 265.//从startPos入手下手
  264. 266.fos.seek(startPos);
  265. 267.intindex=manager.getPage().indexOf("/",8);
  266. 268.Stringhost=manager.getPage().substring(7,index);
  267. 269.//System.out.println(host);
  268. 270.socket=newSocket(host,80);
  269. 271.socket.setSoTimeout(30000);
  270. 272.//写进数据
  271. 273.BufferedWriterwr=newBufferedWriter(newOutputStreamWriter(socket.getOutputStream(),"UTF-8"));
  272. 274.StringBuilderb=newStringBuilder();
  273. 275.b.append("GET"+manager.getPage().substring(index)+"HTTP/1.1
  274. ");
  275. 276.b.append("Host:"+host+"
  276. ");
  277. 277.b.append("Referer:"+(manager.getReferer()==null?manager.getPage():manager.getReferer())+"
  278. ");
  279. 278.b.append("UserAgent:Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;flashget;
  280. ");
  281. 279.b.append("Range:bytes="+startPos+"-"+endPos+"
  282. ");
  283. 280.b.append("
  284. ");
  285. 281.//System.out.println(b.toString());
  286. 282.wr.write(b.toString());
  287. 283.wr.flush();
  288. 284.//上面一段向依据文件写进数据,curPos为以后写进的未知,这里会判别是不是小于endPos,
  289. 285.//假如凌驾endPos就代表该线程已实行终了
  290. 286.bis=newBufferedInputStream(socket.getInputStream());
  291. 287.//读取直到换行
  292. 288.intch;
  293. 289.booleanfoundBR=false;
  294. 290.while(true){
  295. 291.ch=bis.read();
  296. 292.if(ch==0xD){
  297. 293.ch=bis.read();
  298. 294.if(ch==0xA){
  299. 295.if(foundBR){
  300. 296.break;
  301. 297.}
  302. 298.foundBR=true;
  303. 299.}else{
  304. 300.foundBR=false;
  305. 301.}
  306. 302.}else{
  307. 303.foundBR=false;
  308. 304.}
  309. 305.}
  310. 306.intlen=-1;
  311. 307.while(curPos<endPos){
  312. 308.//System.out.println(id+"="+(endPos-curPos));
  313. 309.len=bis.read(buf,0,BUFFER_SIZE);
  314. 310.if(len==-1){
  315. 311.break;
  316. 312.}
  317. 313.fos.write(buf,0,len);
  318. 314.//System.out.println(id+"=WriteOK!");
  319. 315.curPos=curPos+len;
  320. 316.if(curPos>endPos){
  321. 317.//猎取准确读取的字节数
  322. 318.readByte+=len-(curPos-endPos)+1;
  323. 319.}else{
  324. 320.readByte+=len;
  325. 321.}
  326. 322.}
  327. 323.System.out.println("线程"+id+"已下载终了:"+readByte);
  328. 324.}catch(Exceptionex){
  329. 325.timeout=true;
  330. 326.}finally{
  331. 327.if(bis!=null){
  332. 328.try{
  333. 329.bis.close();
  334. 330.}catch(Exceptione){
  335. 331.System.out.println("封闭文件失利(1)!");
  336. 332.}
  337. 333.}
  338. 334.if(fos!=null){
  339. 335.try{
  340. 336.fos.close();
  341. 337.}catch(Exceptione){
  342. 338.System.out.println("封闭文件失利(2)!");
  343. 339.}
  344. 340.}
  345. 341.if(socket!=null){
  346. 342.try{
  347. 343.socket.close();
  348. 344.}catch(Exceptione){
  349. 345.System.out.println("封闭链接失利!");
  350. 346.}
  351. 347.}
  352. 348.}
  353. 349.if(timeout){
  354. 350.System.out.println(id+"timeout,restart...");
  355. 351.newHTTPDownloaderThread(manager,id,curPos,endPos).start();
  356. 352.}else{
  357. 353.manager.finished(id);
  358. 354.}
  359. 355.}
  360. 356.}
复制代码
主要缺点就是:速度比较慢,没有C和C++快
作者: 只想知道    时间: 2015-1-21 06:18
多重继承(以接口取代)等特性,增加了垃圾回收器功能用于回收不再被引用的对象所占据的内存空间,使得程序员不用再为内存管理而担忧。在 Java 1.5 版本中,Java 又引入了泛型编程(Generic Programming)、类型安全的枚举、不定长参数和自动装/拆箱等语言特性。
作者: 飘灵儿    时间: 2015-1-30 09:33
至于JDBC,就不用我多说了,你如果用java编过存取数据库的程序,就应该很熟悉。还有,如果你要用Java编发送电子邮件的程序,你就得看看Javamail 了。
作者: 若天明    时间: 2015-2-1 19:35
你一定会高兴地说,哈哈,原来成为Java高手就这么简单啊!记得Tomjava也曾碰到过一个项目经理,号称Java很简单,只要三个月就可以学会。
作者: 深爱那片海    时间: 2015-2-5 14:12
你快去找一份Java的编程工作来做吧(如果是在校学生可以去做兼职啊),在实践中提高自己,那才是最快的。不过你得祈祷在公司里碰到一个高手,而且他 还愿意不厌其烦地教你,这样好象有点难哦!还有一个办法就是读开放源码的程序了。我们知道开放源码大都出自高手,他们设计合理,考虑周到,再加上有广大的程序员参与,代码的价值自然是字字珠叽,铿锵有力(对不起,偶最近《金装四大才子》看多了)。
作者: 愤怒的大鸟    时间: 2015-2-12 02:45
任职于太阳微系统的詹姆斯·高斯林等人于1990年代初开发Java语言的雏形,最初被命名为Oak,目标设置在家用电器等小型系统的程序语言
作者: 小魔女    时间: 2015-3-2 21:13
是一种为 Internet发展的计算机语言
作者: 灵魂腐蚀    时间: 2015-3-3 19:44
是一种突破用户端机器环境和CPU
作者: 简单生活    时间: 2015-3-11 12:38
还好,SUN提供了Javabean可以把你的JSP中的 Java代码封装起来,便于调用也便于重用。
作者: 金色的骷髅    时间: 2015-3-18 11:23
另外编写和运行Java程序需要JDK(包括JRE),在sun的官方网站上有下载,thinking in java第三版用的JDK版本是1.4,现在流行的版本1.5(sun称作J2SE 5.0,汗),不过听说Bruce的TIJ第四版国外已经出来了,是专门为J2SE 5.0而写的。
作者: 仓酷云    时间: 2015-3-25 18:38
在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前景。




欢迎光临 仓酷云 (http://ckuyun.com/) Powered by Discuz! X3.2