栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android  断点续传的原理剖析与实例讲解

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android  断点续传的原理剖析与实例讲解

 本文所要讲的是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 断点续传的资料整理,后续继续补充相关资料,谢谢大家对本站的支持!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/161240.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号