本文所要讲的是Android断点续传的内容,以实例的形式进行了详细介绍。
一、断点续传的原理
其实断点续传的原理很简单,就是在http的请求上和一般的下载有所不同而已。
打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:
假设服务器域名为www.jizhuomi.com/android,文件名为down.zip。
get /down.zip http/1.1
accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, **; q=.2
仔细看一下就会发现多了一行 range: bytes=2000070-
这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。
服务器收到这个请求以后,返回的信息如下:
206
content-length=106786028
content-range=bytes 2000070-106786027/106786028
date=mon, 30 apr 2001 12:55:20 gmt
etag=w/"02ca57e173c11:95b"
content-type=application/octet-stream
server=microsoft-iis/5.0
last-modified=mon, 30 apr 2001 12:55:20 gmt
和前面服务器返回的信息比较一下,就会发现增加了一行:
content-range=bytes 2000070-106786027/106786028
返回的代码也改为206了,而不再是200了。
知道了以上原理,就可以进行断点续传的编程了。
二、java实现断点续传的关键几点
用什么方法实现提交range: bytes=2000070-?
当然用最原始的socket是肯定能完成的,不过那样太费事了,其实java的net包中提供了这种功能。代码如下:
Java代码
url url = new url("http://www.jizhuomi.com/android/down.zip");
httpurlconnection httpconnection = (httpurlconnection)url.openconnection();
//设置user-agent
httpconnection.setrequestproperty("user-agent","netfox");
//设置断点续传的开始位置
httpconnection.setrequestproperty("range","bytes=2000070");
//获得输入流
inputstream input = httpconnection.getinputstream();
从输入流中取出的字节流就是down.zip文件从2000070开始的字节流。
大家看,其实断点续传用java实现起来还是很简单的吧。
接下来要做的事就是怎么保存获得的流到文件中去了。
保存文件采用的方法:我采用的是io包中的randaccessfile类。
操作相当简单,假设从2000070处开始保存文件,代码如下:
Java代码
randomaccess osavedfile = new randomaccessfile("down.zip","rw");
long npos = 2000070;
//定位文件指针到npos位置
osavedfile.seek(npos);
byte[] b = new byte[1024];
int nread;
//从输入流中读入字节流,然后写到文件中
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测试类。
四、实例源码
下面是源程序:
Java代码
package netfox;
import java.io.*;
import java.net.*;
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","1111",new file(bean.getsfilepath()));
tmpfile = new file(bean.getsfilepath()+file.separator + bean.getsfilename()+".info");
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 == -1)
{
system.err.println("file length is not known!");
}
else if(nfilelength == -2)
{
system.err.println("file is not access!");
}
else
{
for(int i=0;i=400)
{
processerrorcode(responsecode);
return -2; //-2 represent access is error
}
string sheader;
for(int i=1;;i++)
{
//datainputstream in = new datainputstream(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(ioexception e){e.printstacktrace ();}
catch(exception e){e.printstacktrace ();}
utility.log(nfilelength);
return nfilelength;
}
//保存下载信息(文件指针位置)
private void write_npos()
{
try{
output = new dataoutputstream(new fileoutputstream(tmpfile));
output.writeint(nstartpos.length);
for(int i=0;i 0 && nstartpos < nendpos && !bstop)
{
nstartpos += fileaccessi.write(b,0,nread);
//if(nthreadid == 1)
// utility.log("nstartpos = " + nstartpos + ", nendpos = " + nendpos);
}
utility.log("thread " + nthreadid + " is over!");
bdownover = true;
//npos = fileaccessi.write (b,0,nread);
}
catch(exception e){e.printstacktrace ();}
}
}
//打印回应的头信息
public void logresponsehead(httpurlconnection con)
{
for(int i=1;;i++)
{
string header=con.getheaderfieldkey(i);
if(header!=null)
//responseheaders.put(header,httpconnection.getheaderfield(header));
utility.log(header+" : "+con.getheaderfield(header));
else
break;
}
}
public void splitterstop()
{
bstop = true;
}
}
package netfox;
import java.io.*;
public class fileaccessi implements serializable{
randomaccessfile osavedfile;
long npos;
public fileaccessi() throws ioexception
{
this("",0);
}
public fileaccessi(string sname,long npos) throws ioexception
{
osavedfile = new randomaccessfile(sname,"rw");
this.npos = npos;
osavedfile.seek(npos);
}
public synchronized int write(byte[] b,int nstart,int nlen)
{
int n = -1;
try{
osavedfile.write(b,nstart,nlen);
n = nlen;
}
catch(ioexception e)
{
e.printstacktrace ();
}
return n;
}
}
package netfox;
public class siteinfobean {
private string ssiteurl; //sites url
private string sfilepath; //saved files path
private string sfilename; //saved files name
private int nsplitter; //count of splited downloading file
public siteinfobean()
{
//default value of nsplitter is 5
this("","","",5);
}
public siteinfobean(string surl,string spath,string sname,int nspiltter)
{
ssiteurl= surl;
sfilepath = spath;
sfilename = sname;
this.nsplitter = nspiltter;
}
public string getssiteurl()
{
return ssiteurl;
}
public void setssiteurl(string value)
{
ssiteurl = value;
}
public string getsfilepath()
{
return sfilepath;
}
public void setsfilepath(string value)
{
sfilepath = value;
}
public string getsfilename()
{
return sfilename;
}
public void setsfilename(string value)
{
sfilename = value;
}
public int getnsplitter()
{
return nsplitter;
}
public void setnsplitter(int ncount)
{
nsplitter = ncount;
}
}
package netfox;
public class utility {
public utility()
{
}
public static void sleep(int nsecond)
{
try{
thread.sleep(nsecond);
}
catch(exception e)
{
e.printstacktrace ();
}
}
public static void log(string smsg)
{
system.err.println(smsg);
}
public static void log(int smsg)
{
system.err.println(smsg);
}
}
package netfox;
public class testmethod {
public testmethod()
{ ///xx/weblogic60b2_win.exe
try{
siteinfobean bean = new siteinfobean("http://localhost/xx/weblogic60b2_win.exe","l:\temp","weblogic60b2_win.exe",5);
//siteinfobean bean = new siteinfobean("http://localhost:8080/down.zip","l:\temp","weblogic60b2_win.exe",5);
sitefilefetch filefetch = new sitefilefetch(bean);
filefetch.start();
}
catch(exception e){e.printstacktrace ();}
}
public static void main(string[] args)
{
new testmethod();
}
}
以上就是对Android 断点续传的资料整理,后续继续补充相关资料,谢谢大家对本站的支持!



