1,客户端第一次下载
客户端request head信息
GET /test/micro.rar HTTP/1.1
User-Agent:
RANGE: bytes=0-
Host: 10.10.246.126:8983
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
服务端response head信息
HTTP/1.1 206 Partial Content
Last-Modified: Wed, 11 Jan 2012 03:09:24 GMT
Content-Length: 392725947
Accept-Ranges: bytes
Content-Range: bytes 0-392725946/392725947
2,客户端断点续传
客户端request head信息
GET /test/micro.rar HTTP/1.1
User-Agent:
RANGE: bytes=147193856-
Host: 10.10.246.126:8983
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
服务端response head信息
HTTP/1.1 206 Partial Content
Last-Modified: Wed, 11 Jan 2012 03:09:24 GMT
Content-Length: 245532091
Accept-Ranges: bytes
Content-Range: bytes 147193856-392725946/392725947
3,客户端已经下载完毕后,再次下载
客户端request head信息
GET /test/micro.rar HTTP/1.1
User-Agent:
RANGE: bytes=392725947-
Host: 10.10.246.126:8983
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
服务端response head信息
HTTP/1.1 416 Requested Range Not Satisfiable
Last-Modified: Wed, 11 Jan 2012 03:09:24 GMT
Content-Length: 392725947
Accept-Ranges: bytes
Content-Range: bytes */392725947
根据以上特性,可以通过java构造支持断点续传功能服务器与客户端
第一部分:服务器端代码:
File file = new File(location);
if (file.exists()) {
long p = 0;
long fileLength;
fileLength = file.length();
// get file content
InputStream ins = new FileInputStream(file);
bis = new BufferedInputStream(ins);
// tell the client to allow accept-ranges
response.reset();
response.setHeader("Accept-Ranges", "bytes");
// client requests a file block download start byte
if (request.getHeader("Range") != null) {
response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
p = Long.parseLong(request.getHeader("Range")
.replaceAll("bytes=", "")
.replaceAll("-", "")
);
}
// support multi-threaded download
// respone format:
// Content-Length:[file size] - [client request start bytes from file block]
response.setHeader("Content-Length", new Long(fileLength - p).toString());
if (p != 0) {
// 断点开始
// 响应的格式是:
// Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
String contentRange = new StringBuffer("bytes ")
.append(new Long(p).toString())
.append("-")
.append(new Long(fileLength - 1).toString())
.append("/")
.append(new Long(fileLength).toString())
.toString();
response.setHeader("Content-Range", contentRange);
// pointer move to seek
bis.skip(p);
}
String fileName = file.getName();
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
while ((size = bis.read(buf)) != -1) {
response.getOutputStream().write(buf,0,size);
response.getOutputStream().flush();
}
bis.close();
第二部分:客户端代码
public class TestDownload {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HttpURLConnection httpURLConnection = null;
URL url = null;
BufferedInputStream bis = null;
byte[] buf = new byte[10240];
int size = 0;
String fileName = "aaa.zip";
String filePath = "C:\\Users\\Desktop";
String remoteUrl = "http://127.0.0.1:8080/down.zip";
// 检查本地文件
RandomAccessFile rndFile = null;
File file = new File(filePath + "\\" + fileName);
long remoteFileSize = getRemoteFileSzie(remoteUrl);
long nPos = 0;
if (file.exists()) {
long localFileSzie = file.length();
if (localFileSzie < remoteFileSize) {
System.out.println("文件续传...");
nPos = localFileSzie;
} else {
System.out.println("文件存在,重新下载...");
file.delete();
try {
file.createNewFile();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
} else {
// 建立文件
try {
file.createNewFile();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
// 下载文件
try {
url = new URL(remoteUrl);
httpURLConnection = (HttpURLConnection)url.openConnection();
// 设置User-Agent
httpURLConnection.setRequestProperty("User-Agent", "Net");
// 设置续传开始
httpURLConnection.setRequestProperty("Range", "bytes=" + nPos + "-");
// 获取输入流
bis = new BufferedInputStream(httpURLConnection.getInputStream());
rndFile = new RandomAccessFile(filePath + "\\" + fileName, "rw");
rndFile.seek(nPos);
int i = 0;
while ((size = bis.read(buf)) != -1) {
//if (i > 500) break;
rndFile.write(buf, 0, size);
i++;
}
System.out.println("i=" + i);
httpURLConnection.disconnect();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static long getRemoteFileSzie(String url) {
long size = 0;
try {
HttpURLConnection httpUrl = (HttpURLConnection)(new URL(url)).openConnection();
size = httpUrl.getContentLength();
httpUrl.disconnect();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return size;
}
}