Java如何实现HTTP断点续传功能.docx
- 文档编号:8584047
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:17
- 大小:19.25KB
Java如何实现HTTP断点续传功能.docx
《Java如何实现HTTP断点续传功能.docx》由会员分享,可在线阅读,更多相关《Java如何实现HTTP断点续传功能.docx(17页珍藏版)》请在冰豆网上搜索。
Java如何实现HTTP断点续传功能
Java如何实现HTTP断点续传功能
其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已,本文将详细介绍Java如何实现HTTP断点续传功能,需要的朋友可以参考下
.
.
(一)断点续传的原理
其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。
打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:
假设服务器域名为,文件名为down.zip。
GET/down.zipHTTP/1.1
Accept:
image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/vnd.ms-
excel,application/msword,application/vnd.ms-powerpoint,*/*
Accept-Language:
zh-cn
Accept-Encoding:
gzip,deflate
User-Agent:
Mozilla/4.0(compatible;MSIE5.01;WindowsNT5.0)
Connection:
Keep-Alive
服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下
200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon,30Apr200112:
56:
11GMT
ETag=W/"02ca57e173c11:
95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon,30Apr200112:
56:
11GMT
所谓断点续传,也就是要从文件已经下载的地方开始继续下载。
所以在客户端浏览器传给
Web服务器的时候要多加一条信息--从哪里开始。
下面是用自己编的一个"浏览器"来传递请求信息给Web服务器,要求从2000070字节开始。
GET/down.zipHTTP/1.0
User-Agent:
NetFox
RANGE:
bytes=2000070-
Accept:
text/html,image/gif,image/jpeg,*;q=.2,*/*;q=.2
仔细看一下就会发现多了一行RANGE:
bytes=2000070-
这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。
服务器收到这个请求以后,返回的信息如下:
206
Content-Length=106786028
Content-Range=bytes2000070-106786027/106786028
Date=Mon,30Apr200112:
55:
20GMT
ETag=W/"02ca57e173c11:
95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon,30Apr200112:
55:
20GMT
和前面服务器返回的信息比较一下,就会发现增加了一行:
Content-Range=bytes2000070-106786027/106786028
返回的代码也改为206了,而不再是200了。
知道了以上原理,就可以进行断点续传的编程了。
(二)Java实现断点续传的关键几点
(1)用什么方法实现提交RANGE:
bytes=2000070-。
当然用最原始的Socket是肯定能完成的,不过那样太费事了,其实Java的net包中提供了这种功能。
代码如下:
URLurl=newURL("
HttpURLConnectionhttpConnection=(HttpURLConnection)url.openConnection();
//设置User-Agent
httpConnection.setRequestProperty("User-Agent","NetFox");
//设置断点续传的开始位置
httpConnection.setRequestProperty("RANGE","bytes=2000070");
//获得输入流
InputStreaminput=httpConnection.getInputStream();
从输入流中取出的字节流就是down.zip文件从2000070开始的字节流。
大家看,其实断点续传用Java实现起来还是很简单的吧。
接下来要做的事就是怎么保存获得的流到文件中去了。
保存文件采用的方法。
我采用的是IO包中的RandAccessFile类。
操作相当简单,假设从2000070处开始保存文件,代码如下:
复制代码代码如下:
RandomAccessoSavedFile=newRandomAccessFile("down.zip","rw");
longnPos=2000070;
//定位文件指针到nPos位置
oSavedFile.seek(nPos);
byte[]b=newbyte[1024];
intnRead;
//从输入流中读入字节流,然后写到文件中
while((nRead=input.read(b,0,1024))>0)
{
oSavedFile.write(b,0,nRead);
}
怎么样,也很简单吧。
接下来要做的就是整合成一个完整的程序了。
包括一系列的线程控制等等。
(三)断点续传内核的实现
主要用了6个类,包括一个测试类。
SiteFileFetch.java负责整个文件的抓取,控制内部线程(FileSplitterFetch类)。
FileSplitterFetch.java负责部分文件的抓取。
FileAccess.java负责文件的存储。
SiteInfoBean.java要抓取的文件的信息,如文件保存的目录,名字,抓取文件的URL等。
Utility.java工具类,放一些简单的方法。
TestMethod.java测试类。
下面是源程序:
复制代码代码如下:
/*
**SiteFileFetch.java
*/
packageNetFox;
importjava.io.*;
import.*;
publicclassSiteFileFetchextendsThread{
SiteInfoBeansiteInfoBean=null;//文件信息Bean
long[]nStartPos;//开始位置
long[]nEndPos;//结束位置
FileSplitterFetch[]fileSplitterFetch;//子线程对象
longnFileLength;//文件长度
booleanbFirst=true;//是否第一次取文件
booleanbStop=false;//停止标志
FiletmpFile;//文件下载的临时信息
DataOutputStreamoutput;//输出到文件的输出流
publicSiteFileFetch(SiteInfoBeanbean)throwsIOException
{
siteInfoBean=bean;
//tmpFile=File.createTempFile("zhong","1111",newFile(bean.getSFilePath()));
tmpFile=newFile(bean.getSFilePath()+File.separator+bean.getSFileName()+".info");
if(tmpFile.exists())
{
bFirst=false;
read_nPos();
}
else
{
nStartPos=newlong[bean.getNSplitter()];
nEndPos=newlong[bean.getNSplitter()];
}
}
publicvoidrun()
{
//获得文件长度
//分割文件
//实例FileSplitterFetch
//启动FileSplitterFetch线程
//等待子线程返回
try{
if(bFirst)
{
nFileLength=getFileSize();
if(nFileLength==-1)
{
System.err.println("FileLengthisnotknown!
");
}
elseif(nFileLength==-2)
{
System.err.println("Fileisnotaccess!
");
}
else
{
for(inti=0;i { nStartPos[i]=(long)(i*(nFileLength/nStartPos.length)); } for(inti=0;i { nEndPos[i]=nStartPos[i+1]; } nEndPos[nEndPos.length-1]=nFileLength; } } //启动子线程 fileSplitterFetch=newFileSplitterFetch[nStartPos.length]; for(inti=0;i { fileSplitterFetch[i]=newFileSplitterFetch(siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath()+File.separator+siteInfoBean.getSFileName(), nStartPos[i],nEndPos[i],i); Utility.log("Thread"+i+",nStartPos="+nStartPos[i]+",nEndPos="+nEndPos[i]); fileSplitterFetch[i].start(); } //fileSplitterFetch[nPos.length-1]=newFileSplitterFetch(siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath()+File.separator+siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1); //Utility.log("Thread"+(nPos.length-1)+",nStartPos="+nPos[nPos.length-1]+", nEndPos="+nFileLength); //fileSplitterFetch[nPos.length-1].start(); //等待子线程结束 //intcount=0; //是否结束while循环 booleanbreakWhile=false; while(! bStop) { write_nPos(); Utility.sleep(500); breakWhile=true; for(inti=0;i { if(! fileSplitterFetch[i].bDownOver) { breakWhile=false; break; } } if(breakWhile) break; //count++; //if(count>4) //siteStop(); } System.err.println("文件下载结束! "); } catch(Exceptione){e.printStackTrace();} } //获得文件长度 publiclonggetFileSize() { intnFileLength=-1; try{ URLurl=newURL(siteInfoBean.getSSiteURL()); HttpURLConnectionhttpConnection=(HttpURLConnection)url.openConnection(); httpConnection.setRProperty("User-Agent","NetFox"); intresponseCode=httpConnection.getResponseCode(); if(responseCode>=400) { processErrorCode(responseCode); return-2;//-2representaccessiserror } StringsHeader; for(inti=1;;i++) { //DataInputStreamin=newDataInputStream(httpConnection.getInputStream()); //Utility.log(in.readLine()); sHeader=httpConnection.getHeaderFieldKey(i); if(sHeader! =null) { if(sHeader.equals("Content-Length")) { nFileLength=Integer.parseInt(httpConnection.getHeaderField(sHeader)); break; } } else break; } } catch(IOExceptione){e.printStackTrace();} catch(Exceptione){e.printStackTrace();} Utility.log(nFileLength); returnnFileLength; } //保存下载信息(文件指针位置) privatevoidwrite_nPos() { try{ output=newDataOutputStream(newFileOutputStream(tmpFile)); output.writeInt(nStartPos.length); for(inti=0;i { //output.writeLong(nPos[i]); output.writeLong(fileSplitterFetch[i].nStartPos); output.writeLong(fileSplitterFetch[i].nEndPos); } output.close(); } catch(IOExceptione){e.printStackTrace();} catch(Exceptione){e.printStackTrace();} } //读取保存的下载信息(文件指针位置) privatevoidread_nPos() { try{ DataInputStreaminput=newDataInputStream(newFileInputStream(tmpFile)); intnCount=input.readInt(); nStartPos=newlong[nCount]; nEndPos=newlong[nCount]; for(inti=0;i { nStartPos[i]=input.readLong(); nEndPos[i]=input.readLong(); } input.close(); } catch(IOExceptione){e.printStackTrace();} catch(Exceptione){e.printStackTrace();} } privatevoidprocessErrorCode(intnErrorCode) { System.err.println("ErrorCode: "+nErrorCode); } //停止文件下载 publicvoidsiteStop() { bStop=true; for(inti=0;i fileSplitterFetch[i].splitterStop(); } } /* **FileSplitterFetch.java */ packageNetFox; importjava.io.*; import.*; publicclassFileSplitterFetchextendsThread{ StringsURL;//FileURL longnStartPos;//FileSnippetStartPosition longnEndPos;//FileSnippetEndPosition intnThreadID;//Thread'sID booleanbDownOver=false;//Downingisover booleanbStop=false;//Stopidentical FileAccessIfileAccessI=null;//FileAccessinterface publicFileSplitterFetch(StringsURL,StringsName,longnStart,longnEnd,intid)throwsIOException { this.sURL=sURL; this.nStartPos=nStart; this.nEndPos=nEnd; nThreadID=id; fileAccessI=newFileAccessI(sName,nStartPos); } publicvoidrun() { while(nStartPos bStop) { try{ URLurl=newURL(sURL); HttpURLConnectionhttpConnection=(HttpURLConnection)url.openConnection(); httpConnection.setRequestProperty("User-Agent","NetFox"); StringsProperty="bytes="+nStartPos+"-"; httpConnection.setRequestProperty("RANGE",sProperty); Utility.log(sPperty); InputStreaminput=httpConnection.getInputStream(); //logResponseHead(httpConnection); byte[]b=newbyte[1024]; intnRead; while((nRead=input.read(b,0,1024))>0&&nStartPos bStop) { nStartPos+=fileAccessI.write(b,0,nRead); //if(nThreadID==1) //Utility.log("nStartPos="+nStartPos+",nEndPos="+nEndPos); } Utility.log("Thread"+nThreadID+"isover! "); bDownOver=true; //nPos=fileAccessI.write(b,0,nRead); } catch(Exceptione){e.printStackTrace();} } } //打印回应的头信息 publicvoidlogResponseHead(HttpURLConnectioncon) { for(inti=1;;i++) { Stringheader=con.getHeaderFieldKey(i); if(header! =null) //responseHeaders.put(header,httpConnection.getHeaderField(header)); Utility.log(header+": "+con.getHeaderField(header)); else break; } } publicvoidsplitterStop() { bStop=true; } } /* **FileAccess.java */ packageNetFox; importjava.io.*; publicclassFileAccessIimplementsSerializable{ RandomAccessFileoSavedFile; longnPos; publicFileAccessI()throwsIOException { this("",0); } publicFileAccessI(StringsName,longnPos)throwsIOException { oSavedFile=newRandomAccessFile(sNa
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 如何 实现 HTTP 断点续传 功能
![提示](https://static.bdocx.com/images/bang_tan.gif)