java

位置:IT落伍者 >> java >> 浏览文章

用Java实现断点续传(HTTP)


发布日期:2021年10月25日
 
用Java实现断点续传(HTTP)

断点续传的原理

其实断点续传的原理很简单就是在 Http 的请求上和一般的下载有所不同而已

打个比方浏览器请求服务器上的一个文时所发出的请求如下

假设服务器域名为 文件名为 downzip

GET /downzip HTTP/

Accept: image/gif image/xxbitmap image/jpeg image/pjpeg application/vndms

excel application/msword application/vndmspowerpoint */*

AcceptLanguage: zhcn

AcceptEncoding: gzip deflate

UserAgent: Mozilla/ (compatible; MSIE ; Windows NT )

Connection: KeepAlive

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

ContentLength=

AcceptRanges=bytes

Date=Mon Apr :: GMT

ETag=W/caec:b

ContentType=application/octetstream

Server=MicrosoftIIS/

LastModified=Mon Apr :: GMT

所谓断点续传也就是要从文件已经下载的地方开始继续下载所以在客户端浏览器传给 Web 服务器的时候要多加一条信息 从哪里开始

下面是用自己编的一个浏览器来传递请求信息给 Web 服务器要求从 字节开始

GET /downzip HTTP/

UserAgent: NetFox

RANGE: bytes=

Accept: text/html image/gif image/jpeg *; q= */*; q=

仔细看一下就会发现多了一行 RANGE: bytes=

这一行的意思就是告诉服务器 downzip 这个文件从 字节开始传前面的字节不用传了

服务器收到这个请求以后返回的信息如下

ContentLength=

ContentRange=bytes /

Date=Mon Apr :: GMT

ETag=W/caec:b

ContentType=application/octetstream

Server=MicrosoftIIS/

LastModified=Mon Apr :: GMT

和前面服务器返回的信息比较一下就会发现增加了一行

ContentRange=bytes /

返回的代码也改为 而不再是

知道了以上原理就可以进行断点续传的编程了

Java 实现断点续传的关键几点

() 用什么方法实现提交 RANGE: bytes=

当然用最原始的 Socket 是肯定能完成的不过那样太费事了其实 Java 的 net 包中提供了这种功能代码如下

URL url = new URL();

HttpURLConnection httpConnection = (HttpURLConnection)urlopenConnection();

// 设置 UserAgent

(UserAgentNetFox);

// 设置断点续传的开始位置

(RANGEbytes=);

// 获得输入流

InputStream input = ();

从输入流中取出的字节流就是 downzip 文件从 开始的字节流 大家看其实断点续传用 Java 实现起来还是很简单的吧 接下来要做的事就是怎么保存获得的流到文件中去了

保存文件采用的方法

我采用的是 IO 包中的 RandAccessFile 类

操作相当简单假设从 处开始保存文件代码如下

RandomAccess oSavedFile = new RandomAccessFile(downziprw);

long nPos = ;

// 定位文件指针到 nPos 位置

oSavedFileseek(nPos);

byte[] b = new byte[];

int nRead;

// 从输入流中读入字节流然后写到文件中

while((nRead=inputread(b)) > )

{

oSavedFilewrite(bnRead);

}

怎么样也很简单吧 接下来要做的就是整合成一个完整的程序了包括一系列的线程控制等等

断点续传内核的实现

主要用了 个类包括一个测试类

SiteFileFetchjava 负责整个文件的抓取控制内部线程 (FileSplitterFetch 类 )

FileSplitterFetchjava 负责部分文件的抓取

FileAccessjava 负责文件的存储

SiteInfoBeanjava 要抓取的文件的信息如文件保存的目录名字抓取文件的 URL 等

Utilityjava 工具类放一些简单的方法

TestMethodjava 测试类

下面是源程序

/*

/*

* SiteFileFetchjava

*/

package NetFox;

import javaio*;

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 = FilecreateTempFile (zhongnew File(beangetSFilePath()));

tmpFile = new File(beangetSFilePath()+Fileseparator + beangetSFileName()+);

if(tmpFileexists ())

{

bFirst = false;

read_nPos();

}

else

{

nStartPos = new long[beangetNSplitter()];

nEndPos = new long[beangetNSplitter()];

}

}

public void run()

{

// 获得文件长度

// 分割文件

// 实例 FileSplitterFetch

// 启动 FileSplitterFetch 线程

// 等待子线程返回

try{

if(bFirst)

{

nFileLength = getFileSize();

if(nFileLength == )

{

Systemerrprintln(File Length is not known!);

}

else if(nFileLength == )

{

Systemerrprintln(File is not access!);

}

else

{

for(int i=;i<nStartPoslength;i++)

{

nStartPos[i] = (long)(i*(nFileLength/nStartPoslength));

}

for(int i=;i<nEndPoslength;i++)

{

nEndPos[i] = nStartPos[i+];

}

nEndPos[nEndPoslength] = nFileLength;

}

}

// 启动子线程

fileSplitterFetch = new FileSplitterFetch[nStartPoslength];

for(int i=;i<nStartPoslength;i++)

{

fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBeangetSSiteURL()

siteInfoBeangetSFilePath() + Fileseparator + siteInfoBeangetSFileName()

nStartPos[i]nEndPos[i]i);

Utilitylog(Thread + i + nStartPos = + nStartPos[i] + nEndPos =

+ nEndPos[i]);

fileSplitterFetch[i]start();

}

// fileSplitterFetch[nPoslength] = new FileSplitterFetch(siteInfoBeangetSSiteURL()

siteInfoBeangetSFilePath() + Fileseparator

+ siteInfoBeangetSFileName()nPos[nPoslength]nFileLengthnPoslength);

// Utilitylog(Thread +(nPoslength) + nStartPos = +nPos[nPoslength]+

nEndPos = + nFileLength);

// fileSplitterFetch[nPoslength]start();

// 等待子线程结束

//int count = ;

// 是否结束 while 循环

boolean breakWhile = false;

while(!bStop)

{

write_nPos();

Utilitysleep();

breakWhile = true;

for(int i=;i<nStartPoslength;i++)

{

if(!fileSplitterFetch[i]bDownOver)

{

breakWhile = false;

break;

}

}

if(breakWhile)

break;

//count++;

//if(count>)

// siteStop();

}

Systemerrprintln(文件下载结束!);

}

catch(Exception e){eprintStackTrace ();}

}

// 获得文件长度

public long getFileSize()

{

int nFileLength = ;

try{

URL url = new URL(siteInfoBeangetSSiteURL());

HttpURLConnection httpConnection = (HttpURLConnection)urlopenConnection ();

(UserAgentNetFox);

int responseCode=();

if(responseCode>=)

{

processErrorCode(responseCode);

return ; // represent access is error

}

String sHeader;

for(int i=;;i++)

{

//DataInputStream in = new DataInputStream( ());

//Utilitylog(inreadLine());

sHeader=(i);

if(sHeader!=null)

{

if(sHeaderequals(ContentLength))

{

nFileLength = IntegerparseInt((sHeader));

break;

}

}

else

break;

}

}

catch(IOException e){eprintStackTrace ();}

catch(Exception e){eprintStackTrace ();}

Utilitylog(nFileLength);

return nFileLength;

}

// 保存下载信息(文件指针位置)

private void write_nPos()

{

try{

output = new DataOutputStream(new FileOutputStream(tmpFile));

outputwriteInt(nStartPoslength);

for(int i=;i<nStartPoslength;i++)

{

// outputwriteLong(nPos[i]);

outputwriteLong(fileSplitterFetch[i]nStartPos);

outputwriteLong(fileSplitterFetch[i]nEndPos);

}

outputclose();

}

catch(IOException e){eprintStackTrace ();}

catch(Exception e){eprintStackTrace ();}

}

// 读取保存的下载信息(文件指针位置)

private void read_nPos()

{

try{

DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));

int nCount = inputreadInt();

nStartPos = new long[nCount];

nEndPos = new long[nCount];

for(int i=;i<nStartPoslength;i++)

{

nStartPos[i] = inputreadLong();

nEndPos[i] = inputreadLong();

}

inputclose();

}

catch(IOException e){eprintStackTrace ();}

catch(Exception e){eprintStackTrace ();}

}

private void processErrorCode(int nErrorCode)

{

Systemerrprintln(Error Code : + nErrorCode);

}

// 停止文件下载

public void siteStop()

{

bStop = true;

for(int i=;i<nStartPoslength;i++)

fileSplitterFetch[i]splitterStop();

}

}

/*

**FileSplitterFetchjava

*/

package NetFox;

import javaio*;

import *;

public class FileSplitterFetch extends Thread {

String sURL; //File URL

long nStartPos; //File Snippet Start Position

long nEndPos; //File Snippet End Position

int nThreadID; //Threads ID

boolean bDownOver = false; //Downing is over

boolean bStop = false; //Stop identical

FileAccessI fileAccessI = null; //File Access interface

public FileSplitterFetch(String sURLString sNamelong nStartlong nEndint id)

throws IOException

{

thissURL = sURL;

thisnStartPos = nStart;

thisnEndPos = nEnd;

nThreadID = id;

fileAccessI = new FileAccessI(sNamenStartPos);

}

public void run()

{

while(nStartPos < nEndPos && !bStop)

{

try{

URL url = new URL(sURL);

HttpURLConnection httpConnection = (HttpURLConnection)urlopenConnection ();

(UserAgentNetFox);

String sProperty = bytes=+nStartPos+;

(RANGEsProperty);

Utilitylog(sProperty);

InputStream input = ();

//logResponseHead(httpConnection);

byte[] b = new byte[];

int nRead;

while((nRead=inputread(b)) > && nStartPos < nEndPos

&& !bStop)

{

nStartPos += fileAccessIwrite(bnRead);

//if(nThreadID == )

// Utilitylog(nStartPos = + nStartPos + nEndPos = + nEndPos);

}

Utilitylog(Thread + nThreadID + is over!);

bDownOver = true;

//nPos = fileAccessIwrite (bnRead);

}

catch(Exception e){eprintStackTrace ();}

}

}

// 打印回应的头信息

public void logResponseHead(HttpURLConnection con)

{

for(int i=;;i++)

{

String header=congetHeaderFieldKey(i);

if(header!=null)

//responseHeadersput(header(header));

Utilitylog(header+ : +congetHeaderField(header));

else

break;

}

}

public void splitterStop()

{

bStop = true;

}

}

/*

**FileAccessjava

*/

package NetFox;

import javaio*;

public class FileAccessI implements Serializable{

RandomAccessFile oSavedFile;

long nPos;

public FileAccessI() throws IOException

{

this();

}

public FileAccessI(String sNamelong nPos) throws IOException

{

oSavedFile = new RandomAccessFile(sNamerw);

thisnPos = nPos;

oSavedFileseek(nPos);

}

public synchronized int write(byte[] bint nStartint nLen)

{

int n = ;

try{

oSavedFilewrite(bnStartnLen);

n = nLen;

}

catch(IOException e)

{

eprintStackTrace ();

}

return n;

}

}

/*

**SiteInfoBeanjava

*/

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

this();

}

public SiteInfoBean(String sURLString sPathString sNameint nSpiltter)

{

sSiteURL= sURL;

sFilePath = sPath;

sFileName = sName;

thisnSplitter = 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;

}

}

/*

**Utilityjava

*/

package NetFox;

public class Utility {

public Utility()

{

}

public static void sleep(int nSecond)

{

try{

Threadsleep(nSecond);

}

catch(Exception e)

{

eprintStackTrace ();

}

}

public static void log(String sMsg)

{

Systemerrprintln(sMsg);

}

public static void log(int sMsg)

{

Systemerrprintln(sMsg);

}

}

/*

**TestMethodjava

*/

package NetFox;

public class TestMethod {

public TestMethod()

{ ///xx/weblogicb_winexe

try{

SiteInfoBean bean = new SiteInfoBean(

L:\\tempweblogicb_winexe);

//SiteInfoBean bean = new SiteInfoBean(L:\\temp

weblogicb_winexe);

SiteFileFetch fileFetch = new SiteFileFetch(bean);

fileFetchstart();

}

catch(Exception e){eprintStackTrace ();}

}

public static void main(String[] args)

{

new TestMethod();

}

}

               

上一篇:Java利用smslib发送短信

下一篇:Java全屏带分辨率设置