java中http断点续传的原理(1)
java中https断点续传的原理(1)
(一)断点续传的原理
其实断点续传的原理很简单 就是在Http的请求上和一般的下载有所不同而已
打个比方 浏览器请求服务器上的一个文时 所发出的请求如下
假设服务器域名为 文件名为down zip
GET /down zip HTTP/
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/ (patible; MSIE ; Windows NT )
Connection: Keep Alive
服务器收到请求后 按要求寻找请求的文件 提取文件的信息 然后返回给浏览器 返回信息如下
Content Length=
Accept Ranges=bytes
Date=Mon Apr : : GMT
ETag=W/ ca e c : b
Content Type=application/octet stream
Server=Microsoft IIS/
Last Modified=Mon Apr : : GMT
所谓断点续传 也就是要从文件已经下载的地方开始继续下载 所以在客户端浏览器传给
Web服务器的时候要多加一条信息 从哪里开始
下面是用自己编的一个 浏览器 来传递请求信息给Web服务器 要求从 字节开始
GET /down zip HTTP/
User Agent: NetFox
RANGE: bytes=
Accept: text/ image/gif image/jpeg *; q= */*; q=
仔细看一下就会发现多了一行RANGE: bytes=
这一行的意思就是告诉服务器down zip这个文件从 字节开始传 前面的字节不用传了
服务器收到这个请求以后 返回的信息如下
Content Length=
Content Range=bytes /
Date=Mon Apr : : GMT
ETag=W/ ca e c : b
Content Type=application/octet stream
Server=Microsoft IIS/
Last Modified=Mon Apr : : GMT
和前面服务器返回的信息比较一下 就会发现增加了一行
Content Range=bytes /
返回的代码也改为 了 而不再是 了
知道了以上原理 就可以进行断点续传的编程了
(二)Java实现断点续传的关键几点
( )用什么方法实现提交RANGE: bytes=
当然用最原始的Socket是肯定能完成的 不过那样太费事了 其实Java的net包中提供了这种功能 代码如下
URL url = new URL( );
HttpURLConnection Connection = (HttpURLConnection)url openConnection
();
//设置User Agent
( User Agent NetFox );

//设置断点续传的开始位置
( RANGE bytes= );
//获得输入流
InputStream input = ();
从输入流中取出的字节流就是down zip文件从 开始的字节流
大家看 其实断点续传用Java实现起来还是很简单的吧
接下来要做的事就是怎么保存获得的流到文件中去了
保存文件采用的方法
我采用的是IO包中的RandAccessFile类
操作相当简单 假设从 处开始保存文件 代码如下
RandomAccess oSavedFile = new RandomAccessFile( down zip rw );
long nPos = ;
//定位文件指针到nPos位置
oSavedFile seek(nPos);
byte[] b = new byte[ ];
int nRead;
//从输入流中读入字节流 然后写到文件中
while((nRead=input read(b )) > )
{
oSavedFile write(b nRead);
}
怎么样 也很简单吧
接下来要做的就是整合成一个完整的程序了 包括一系列的线程控制等等
(三)断点续传内核的实现
主要用了 个类 包括一个测试类
SiteFileFetch java负责整个文件的抓取 控制内部线程(FileSplitterFetch类)
FileSplitterFetch java负责部分文件的抓取
FileAccess java负责文件的存储
SiteInfoBean java要抓取的文件的信息 如文件保存的目录 名字 抓取文件的URL等
Utility java工具类 放一些简单的方法
TestMethod java测试类
下面是源程序
/*
**SiteFileFetch java
*/
package NetFox;
import java io *;
import *;
public class SiteFileFetch extends Thread {
SiteInfoBean siteInfoBean = null; //文件信息Bean
long[] nStartPos; //开始位置
long[] nEndPos; //结束位置
FileSplitterFetch[] fileSplitterFetch; //子线程对象
long nFileLength; //文件长度
boolean bFirst = true; //是否第一次取文件
boolean bStop = false; //停止标志
File tmpFile; //文件下载的临时信息
DataOutputStream output; //输出到文件的输出流
public SiteFileFetch(SiteInfoBean bean) throws IOException
{
siteInfoBean = bean;
//tmpFile = File createTempFile ( zhong new File(bean getSFilePath()));
tmpFile = new File(bean getSFilePath()+File separator + bean getSFileName()+ );
if(tmpFile exists ())
{
bFirst = false;
read_nPos();
}
else
{
nStartPos = new long[bean getNSplitter()];
nEndPos = new long[bean getNSplitter()];
}
}
public void run()
{
//获得文件长度
//分割文件
//实例FileSplitterFetch
//启动FileSplitterFetch线程
//等待子线程返回
try{
if(bFirst)
{
nFileLength = getFileSize();
if(nFileLength == )
{
System err println( File Length is not known! );
}
else if(nFileLength == )
{
System err println( File is not access! );
}
else
{
for(int i= ;i<nStartPos length;i++)
{
nStartPos[i] = (long)(i*(nFileLength/nStartPos length));
}
for(int i= ;i<nEndPos length ;i++)
{
nEndPos[i] = nStartPos[i+ ];
}
nEndPos[nEndPos length ] = nFileLength;
}
}
//启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos length];
for(int i= ;i<nStartPos length;i++)
{
fileSplitterFetch[i] = new FileSplitterFetch(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 ] = new FileSplitterFetch(siteInfoBean getSSiteURL()
siteInfoBean getSFilePath() + File separator + siteInfoBean getSFileName() nPos[nPos length ] nFileLength nPos length );
// Utility log( Thread + (nPos length ) + nStartPos = + nPos[nPos length ] +
nEndPos = + nFileLength);
// fileSplitterFetch[nPos length ] start();
//等待子线程结束
//int count = ;
//是否结束while循环
boolean breakWhile = false;
while(!bStop)
{
write_nPos();
Utility sleep( );
breakWhile = true;
for(int i= ;i<nStartPos length;i++)
{
if(!fileSplitterFetch[i] bDownOver)
{
breakWhile = false;
break;
}
}
if(breakWhile)
break;
//count++;
//if(count> )
// siteStop();
}
System err println( 文件下载结束! );
}
catch(Exception e){e printStackTrace ();}
lishixinzhi/Article/program/Java/hx/201311/26964