- 浏览: 138270 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
i523853827:
楼主你好,文章里面有错误,希望楼主能改正 验证的xml 是类名 ...
struts校验框架学习总结 -
renjy1123:
希望楼主分享下,我现在也要用,也不知如何着手,纠结!
OSB学习 -
fengweiyou:
说的非常好,如果不说还真不知道是哪里的问题呢。谢谢你
struts2.1.8+spring2.5.6+hibernate3.2框架搭建错误 -
2001430:
...
There is no Action mapped for action name XX.的解决 -
chilongxph:
楼上正解,此种方式的问题正在与此,如果过多的话,就只能去使用存 ...
oracle 列转行
断点续传的原理
其实断点续传的原理很简单,就是在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测试类。
下面是源程序:
Java代码
/*
**SiteFileFetch.java
*/
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
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.length; i++) {
nStartPos[i] = (long) (i * (nFileLength / nStartPos.length));
}
for (int i = 0; i < nEndPos.length - 1; i++) {
nEndPos[i] = nStartPos[i + 1];
}
nEndPos[nEndPos.length - 1] = nFileLength;
}
}
// 启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
for (int i = 0; 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-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 < nStartPos.length; 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 < nStartPos.length; 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();
}
}
// 读取保存的下载信息(文件指针位置)
private void read_nPos() {
try {
DataInputStream input = new DataInputStream(new FileInputStream(
tmpFile));
int nCount = input.readInt();
nStartPos = new long[nCount];
nEndPos = new long[nCount];
for (int i = 0; i < nStartPos.length; i++) {
nStartPos[i] = input.readLong();
nEndPos[i] = input.readLong();
}
input.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void processErrorCode(int nErrorCode) {
System.err.println("Error Code : " + nErrorCode);
}
// 停止文件下载
public void siteStop() {
bStop = true;
for (int i = 0; i < nStartPos.length; i++)
fileSplitterFetch[i].splitterStop();
}
}
/*
**SiteFileFetch.java
*/
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
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.length; i++) {
nStartPos[i] = (long) (i * (nFileLength / nStartPos.length));
}
for (int i = 0; i < nEndPos.length - 1; i++) {
nEndPos[i] = nStartPos[i + 1];
}
nEndPos[nEndPos.length - 1] = nFileLength;
}
}
// 启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
for (int i = 0; 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-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 < nStartPos.length; 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 < nStartPos.length; 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();
}
}
// 读取保存的下载信息(文件指针位置)
private void read_nPos() {
try {
DataInputStream input = new DataInputStream(new FileInputStream(
tmpFile));
int nCount = input.readInt();
nStartPos = new long[nCount];
nEndPos = new long[nCount];
for (int i = 0; i < nStartPos.length; i++) {
nStartPos[i] = input.readLong();
nEndPos[i] = input.readLong();
}
input.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void processErrorCode(int nErrorCode) {
System.err.println("Error Code : " + nErrorCode);
}
// 停止文件下载
public void siteStop() {
bStop = true;
for (int i = 0; i < nStartPos.length; i++)
fileSplitterFetch[i].splitterStop();
}
}
Java代码
/*
**FileSplitterFetch.java
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
public class FileSplitterFetch extends Thread {
String sURL; // File URL
long nStartPos; // File Snippet Start Position
long nEndPos; // File Snippet End Position
int nThreadID; // Thread's ID
boolean bDownOver = false; // Downing is over
boolean bStop = false; // Stop identical
FileAccessI fileAccessI = null; // File Access interface
public FileSplitterFetch(String sURL, String sName, long nStart, long nEnd,
int id) throws IOException {
this.sURL = sURL;
this.nStartPos = nStart;
this.nEndPos = nEnd;
nThreadID = id;
fileAccessI = new FileAccessI(sName, nStartPos);
}
public void run() {
while (nStartPos < nEndPos && !bStop) {
try {
URL url = new URL(sURL);
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();
httpConnection.setRequestProperty("User-Agent", "NetFox");
String sProperty = "bytes=" + nStartPos + "-";
httpConnection.setRequestProperty("RANGE", sProperty);
Utility.log(sProperty);
InputStream input = httpConnection.getInputStream();
// logResponseHead(httpConnection);
byte[] b = new byte[1024];
int nRead;
while ((nRead = input.read(b, 0, 1024)) > 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;
}
}
/*
**FileSplitterFetch.java
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
public class FileSplitterFetch extends Thread {
String sURL; // File URL
long nStartPos; // File Snippet Start Position
long nEndPos; // File Snippet End Position
int nThreadID; // Thread's ID
boolean bDownOver = false; // Downing is over
boolean bStop = false; // Stop identical
FileAccessI fileAccessI = null; // File Access interface
public FileSplitterFetch(String sURL, String sName, long nStart, long nEnd,
int id) throws IOException {
this.sURL = sURL;
this.nStartPos = nStart;
this.nEndPos = nEnd;
nThreadID = id;
fileAccessI = new FileAccessI(sName, nStartPos);
}
public void run() {
while (nStartPos < nEndPos && !bStop) {
try {
URL url = new URL(sURL);
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();
httpConnection.setRequestProperty("User-Agent", "NetFox");
String sProperty = "bytes=" + nStartPos + "-";
httpConnection.setRequestProperty("RANGE", sProperty);
Utility.log(sProperty);
InputStream input = httpConnection.getInputStream();
// logResponseHead(httpConnection);
byte[] b = new byte[1024];
int nRead;
while ((nRead = input.read(b, 0, 1024)) > 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;
}
}
Java代码
/*
**FileAccess.java
*/
import java.io.*;
public class FileAccessI implements Serializable {
/** */
private static final long serialVersionUID = 265981599353224785L;
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;
}
}
/*
**FileAccess.java
*/
import java.io.*;
public class FileAccessI implements Serializable {
/** */
private static final long serialVersionUID = 265981599353224785L;
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;
}
}
Java代码
/*
**SiteInfoBean.java
*/
public class SiteInfoBean {
private String sSiteURL; // Site's URL
private String sFilePath; // Saved File's Path
private String sFileName; // Saved File's 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;
}
}
/*
**SiteInfoBean.java
*/
public class SiteInfoBean {
private String sSiteURL; // Site's URL
private String sFilePath; // Saved File's Path
private String sFileName; // Saved File's 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;
}
}
Java代码
/*
**Utility.java
*/
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);
}
}
/*
**Utility.java
*/
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);
}
}
Java代码
/*
**TestMethod.java
*/
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();
}
}
其实断点续传的原理很简单,就是在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测试类。
下面是源程序:
Java代码
/*
**SiteFileFetch.java
*/
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
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.length; i++) {
nStartPos[i] = (long) (i * (nFileLength / nStartPos.length));
}
for (int i = 0; i < nEndPos.length - 1; i++) {
nEndPos[i] = nStartPos[i + 1];
}
nEndPos[nEndPos.length - 1] = nFileLength;
}
}
// 启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
for (int i = 0; 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-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 < nStartPos.length; 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 < nStartPos.length; 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();
}
}
// 读取保存的下载信息(文件指针位置)
private void read_nPos() {
try {
DataInputStream input = new DataInputStream(new FileInputStream(
tmpFile));
int nCount = input.readInt();
nStartPos = new long[nCount];
nEndPos = new long[nCount];
for (int i = 0; i < nStartPos.length; i++) {
nStartPos[i] = input.readLong();
nEndPos[i] = input.readLong();
}
input.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void processErrorCode(int nErrorCode) {
System.err.println("Error Code : " + nErrorCode);
}
// 停止文件下载
public void siteStop() {
bStop = true;
for (int i = 0; i < nStartPos.length; i++)
fileSplitterFetch[i].splitterStop();
}
}
/*
**SiteFileFetch.java
*/
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
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.length; i++) {
nStartPos[i] = (long) (i * (nFileLength / nStartPos.length));
}
for (int i = 0; i < nEndPos.length - 1; i++) {
nEndPos[i] = nStartPos[i + 1];
}
nEndPos[nEndPos.length - 1] = nFileLength;
}
}
// 启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
for (int i = 0; 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-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 < nStartPos.length; 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 < nStartPos.length; 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();
}
}
// 读取保存的下载信息(文件指针位置)
private void read_nPos() {
try {
DataInputStream input = new DataInputStream(new FileInputStream(
tmpFile));
int nCount = input.readInt();
nStartPos = new long[nCount];
nEndPos = new long[nCount];
for (int i = 0; i < nStartPos.length; i++) {
nStartPos[i] = input.readLong();
nEndPos[i] = input.readLong();
}
input.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void processErrorCode(int nErrorCode) {
System.err.println("Error Code : " + nErrorCode);
}
// 停止文件下载
public void siteStop() {
bStop = true;
for (int i = 0; i < nStartPos.length; i++)
fileSplitterFetch[i].splitterStop();
}
}
Java代码
/*
**FileSplitterFetch.java
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
public class FileSplitterFetch extends Thread {
String sURL; // File URL
long nStartPos; // File Snippet Start Position
long nEndPos; // File Snippet End Position
int nThreadID; // Thread's ID
boolean bDownOver = false; // Downing is over
boolean bStop = false; // Stop identical
FileAccessI fileAccessI = null; // File Access interface
public FileSplitterFetch(String sURL, String sName, long nStart, long nEnd,
int id) throws IOException {
this.sURL = sURL;
this.nStartPos = nStart;
this.nEndPos = nEnd;
nThreadID = id;
fileAccessI = new FileAccessI(sName, nStartPos);
}
public void run() {
while (nStartPos < nEndPos && !bStop) {
try {
URL url = new URL(sURL);
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();
httpConnection.setRequestProperty("User-Agent", "NetFox");
String sProperty = "bytes=" + nStartPos + "-";
httpConnection.setRequestProperty("RANGE", sProperty);
Utility.log(sProperty);
InputStream input = httpConnection.getInputStream();
// logResponseHead(httpConnection);
byte[] b = new byte[1024];
int nRead;
while ((nRead = input.read(b, 0, 1024)) > 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;
}
}
/*
**FileSplitterFetch.java
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
public class FileSplitterFetch extends Thread {
String sURL; // File URL
long nStartPos; // File Snippet Start Position
long nEndPos; // File Snippet End Position
int nThreadID; // Thread's ID
boolean bDownOver = false; // Downing is over
boolean bStop = false; // Stop identical
FileAccessI fileAccessI = null; // File Access interface
public FileSplitterFetch(String sURL, String sName, long nStart, long nEnd,
int id) throws IOException {
this.sURL = sURL;
this.nStartPos = nStart;
this.nEndPos = nEnd;
nThreadID = id;
fileAccessI = new FileAccessI(sName, nStartPos);
}
public void run() {
while (nStartPos < nEndPos && !bStop) {
try {
URL url = new URL(sURL);
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();
httpConnection.setRequestProperty("User-Agent", "NetFox");
String sProperty = "bytes=" + nStartPos + "-";
httpConnection.setRequestProperty("RANGE", sProperty);
Utility.log(sProperty);
InputStream input = httpConnection.getInputStream();
// logResponseHead(httpConnection);
byte[] b = new byte[1024];
int nRead;
while ((nRead = input.read(b, 0, 1024)) > 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;
}
}
Java代码
/*
**FileAccess.java
*/
import java.io.*;
public class FileAccessI implements Serializable {
/** */
private static final long serialVersionUID = 265981599353224785L;
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;
}
}
/*
**FileAccess.java
*/
import java.io.*;
public class FileAccessI implements Serializable {
/** */
private static final long serialVersionUID = 265981599353224785L;
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;
}
}
Java代码
/*
**SiteInfoBean.java
*/
public class SiteInfoBean {
private String sSiteURL; // Site's URL
private String sFilePath; // Saved File's Path
private String sFileName; // Saved File's 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;
}
}
/*
**SiteInfoBean.java
*/
public class SiteInfoBean {
private String sSiteURL; // Site's URL
private String sFilePath; // Saved File's Path
private String sFileName; // Saved File's 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;
}
}
Java代码
/*
**Utility.java
*/
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);
}
}
/*
**Utility.java
*/
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);
}
}
Java代码
/*
**TestMethod.java
*/
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();
}
}
发表评论
-
SVN插件问题
2013-12-25 15:42 754将MyEclipse换成了eclipse,安装SVN插件后,却 ... -
Eclipse中project项目转web项目
2013-12-25 15:34 6872项目被搭建成了project项目,感觉很别扭,所以,手动进行了 ... -
sftp同步远程服务器文件
2010-10-15 14:25 3288public class SftpTool { privat ... -
使用dom4j操作xml文档
2009-12-01 13:57 11581. 获取文档对象: public static Docume ... -
使用poi导出excel
2009-12-01 11:22 1632private void writeBackupSoftExc ... -
dom4j
2009-09-29 01:39 1194package xml.dom4j.wkjava; impor ... -
LDAP学习手册节选
2009-09-04 17:52 5222一. ... -
单点登录
2009-08-12 17:49 1233摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软 ... -
js打包
2009-08-04 09:21 2591项目中需要对javascript进行打包和压缩,我选用了yu ... -
利用filter实现MVC应用框架 及 网页编码问题的解决方案
2009-04-28 00:19 1286利用filter实现MVC应用框架 及 网页编码问题的解决方案 ... -
动态代理类
2008-11-27 19:51 1024动态代理类 Java动态代理类位于Java.lang.re ... -
ffmpeg转换参数和对几种视频格式的转换分析
2008-11-19 13:33 1510日志源地址:http://j2ee.blog.sohu.c ... -
网页在线播放器代码大全
2008-11-19 11:47 1483网页在线播放器代码大全 1.avi格式 <objec ... -
Java将视频转换为flash
2008-11-19 11:43 1688Java将视频转换为flash 为这个问题头痛了好久,今天看 ... -
java环境变量设置方法完全版
2008-11-12 10:34 2241Java编程首要工作就是安 ... -
java工作者常用网站
2008-09-20 23:38 1201[b]www.iteye.com[/b] [align=cen ...
相关推荐
Java实现断点续传是一项在文件传输中非常实用的技术,特别是在大文件传输或者网络不稳定的情况下。断点续传允许用户在文件传输中断后从上次中断的位置继续,而不是重新开始整个传输过程,极大地提高了效率和用户体验...
### 用Java实现断点续传的技术解析 #### 一、技术原理概述 断点续传是一种在网络连接不稳定或在下载过程中出现意外中断时能够继续完成下载的技术。它通过记录下载过程中断时的位置,当重新启动下载任务时,可以从...
Java实现断点续传程序是一项在文件传输领域中常见的技术,尤其在大文件下载或上传时,能够提高效率并提供良好的用户体验。以下是关于这个主题的详细讲解。 **断点续传的原理** 断点续传的基本思想是允许用户在文件...
【Java实现断点续传的关键几点】 1. **文件分块**:将大文件分成若干个小块进行传输,这样可以根据每块的完成情况来决定是否需要重新下载。 2. **状态记录**:在下载过程中,记录下每个文件块的下载进度,包括已...
### Java实现断点续传的关键几点 1. 客户端在发送请求时设置Range头,指定需要下载的文件的起始字节位置。 2. 服务器端需要检查请求头中的Range字段,确定要返回的文件范围,并在响应头中设置Content-Range字段。 3...
用apache的FTP实现断点续传 - janestone的专栏 - 博客频道 - CSDN.NET (2012年5月21日) java实现FTP多线程断点续传,上传下载! - java学习与交流 - j2ee学习网 - j2ee学习网 (2012年5月21日) 用 Java 实现断点续传 ...
java实现断点续传 private void setHeader(URLConnection con) { con .setRequestProperty( "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 ...
### Java实现断点续传的关键技术点 #### 1. 使用`HttpURLConnection`发送`RANGE`请求头 为了实现断点续传功能,客户端需要告诉服务器它希望从哪个位置开始下载文件。这是通过向服务器发送一个带有特殊`RANGE`请求...
Java作为一款广泛使用的编程语言,也提供了实现断点续传的能力。本篇文章将深入探讨如何用Java实现HTTP协议下的断点续传功能。 断点续传主要涉及两个关键部分:客户端和服务器端。客户端负责保存已下载的数据状态,...
Java实现断点续传主要涉及以下几个关键步骤: 1. **检测本地文件状态**:首先,程序需要检查本地是否有部分已下载的文件,以及当前文件的大小。如果存在部分文件,记录其长度作为续传的起点。 2. **构建Range请求*...
本项目是一个基于Vue和Java的断点续传与大文件上传系统设计源码,共包含563个文件,其中包括258个Java文件、82个SVG文件等。系统采用了Vue-uploader和若依框架,为用户提供了一个便捷的文件上传解决方案。系统支持多...
下面将详细阐述Java实现断点续传上传的关键技术和步骤。 一、理解断点续传原理 断点续传的基本思想是保存已上传部分的信息,包括已上传的文件大小和最后的偏移位置。当上传中断后,服务器和客户端都保存这个信息,...
下面我们将深入探讨Java实现断点续传的原理和关键点。 1. **断点续传的原理**: 断点续传的核心在于保存已下载部分的信息,通常包括已下载的文件大小、最后的偏移位置等。当下载中断后,系统会记录当前的下载状态...