动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
电脑书籍下载:程序设计书籍 | 数据库教程书籍 | 平面与多媒体书籍 | 网络通讯书籍 | 系统管理书籍 | 网络安全书籍 | 认证考试书籍
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Java教程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ Java教程 ]的信息



本月文章推荐
.如何使用Java编写多线程程序(1).
.GetFileName 方法.
.java实现的18位身份证格式验证算.
.什么是AOP系列之二:AOP与权限控.
.在Eclipse 3.1中体验J2SE 5.0的新.
.使用Jakarta Commons Pool处理对.
.分享关于Java语言中的函数编程.
.Castor JDO 入门.
.Enterprise bean的开发(1).
.Java Swing中使用双击事件.
.JML起步--使用JML 改进你的Java程.
.Jakarta Struts应用的七个经验(.
.WebWork2与SpringFramework集成之.
.Java中的String、StringBuffer和.
.利用反射简化Struts的ActionForm.
.使用ActionHandler进行WEB应用编.
.剖析.Net下的数据访问层技术(1).
.JavaMail 发送附件的例子.
.Spring WebFlow:4(Spring MVC和W.
.Java进阶:编写跨平台Java程序注.

用Java实现断点续传

发表日期:2008-1-5 |


(一)断点续传的原理
其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。
打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:
假设服务器域名为wwww.sjtu.edu.cn,文件名为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, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive


服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:


200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT


所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给
Web服务器的时候要多加一条信息--从哪里开始。
下面是用自己编的一个"浏览器"来传递请求信息给Web服务器,要求从2000070字节开始。
GET /down.zip HTTP/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=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实现断点续传的要害几点


(1)用什么方法实现提交RANGE: bytes=2000070-。
当然用最原始的Socket是肯定能完成的,不过那样太费事了,其实Java的net包中提供了这种功能。代码如下:
URL url = new URL("http://www.sjtu.edu.cn/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处开始保存文件,代码如下:
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测试类。


下面是源程序:
/*
**SiteFileFetch.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{
nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));
}
for(int i=0;i{
nEndPos[i] = nStartPos[i+1];
}
nEndPos[nEndPos.length-1] = nFileLength;
}
}


//启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
for(int i=0;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-1] = new FileSplitterFetch(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();


//等待子线程结束
//int count = 0;
//是否结束while循环
boolean breakWhile = false;


while(!bStop)
{
write_nPos();
Utility.sleep(500);
breakWhile = true;


for(int i=0;i{
if(!fileSplitterFetch[i].bDownOver)
{
breakWhile = false;
break;
}
}
if(breakWhile)
break;


//count++;
//if(count>4)
// siteStop();
}


System.err.println("文件下载结束!");
}
catch(Exception e){e.printStackTrace ();}
}


//获得文件长度
public long getFileSize()
{
int nFileLength = -1;
try{
URL url = new URL(siteInfoBean.getSSiteURL());
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
httpConnection.setRequestProperty("User-Agent","NetFox");


int responseCode=httpConnection.getResponseCode();
if(responseCode>=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{
// output.writeLong(nPos[i]);
output.writeLong(fileSplitterFetch[i].nStartPos);
output.writeLong(fileSplitterFetch[i].nEndPos);
}
output.close();
}
catch(IOException e){e.printStackTrace ();}
catch(Exception e){e.printStackTrace ();}
}

上一篇:用Java简单实现文件分割与合并 人气:418
下一篇:对象引用是怎样严重影响垃圾收集器的 人气:283
浏览全部Java的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-7-25 WikyBlog v1.7.0.1 多国语言版
2008-7-25 乐彼网上开店系统(56770 Eshop)
2008-7-25 赛特网站管理系统sitecms v3.6.0
2008-7-25 Modoer多功能点评系统 v1.0.1 Bu
2008-7-25 Shangducms Teamsuit! v1.1.0 开
2008-7-25 幻影动漫网视频系统(Ppdong) v1.
2008-7-25 acteecompany企业网站建设系统 v
2008-7-25 恒浪整合管理系统 ims v4.1 ACCE
2008-7-25 艺术图库系统 v1.0 beta
2008-7-19 UltraEdit 简体中文增强版 14.10
2008-7-19 CentOS 5.2 i386 LiveCD
2008-7-19 Snapture多功能相机 v1.4
2008-7-19 iAcces中文输入法 v1.0Build016
2008-7-19 Cookbook烹饪秘籍 v2.5
2008-7-19 苹果专用DVD转换工具 v1.1.59汉化
2008-7-19 Modem修复软件ZiPhone修改版04.0
2008-7-19 AgileMessenger即时通讯工具美化
2008-7-19 Sketches画图软件 v0.7b6破解版


  发表评论
姓 名: 验证码:
内 容:
[ 汉字翻译拼音 ] [ 广告代码 ] [ 符号对照表 ] [ 进制转换 ] [ 经典小工具 ] [ 个税计算 ] [ 汉字简繁转换 ] [ 普通单位换算 ] [ 公制单位换算 ]
[ 生辰老黄历 ] [ 国内电话区号 ] [ 国家代码与域名缩写 ] [ 文字加密解密 ] [ 健康查询 ] [ 万年历 ] [ 手机号码查询 ] [ ip搜索 ] [ Google PR查询 ]
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵