您的位置:首页 > 编程语言 > Java开发

Java 支持断点续传功能实现

2016-01-14 16:20 756 查看
服务器端代码:

package *;

import java.io.*;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import biz.etao.appmarket.core.utils.StringUtil;

/**
* 客户端下载文件的统一入口 已支持断点续传
*
* @author lianggj,charlie.deng
*/
@WebServlet(value = "/download/*")
public class FileDownloadServlet extends HttpServlet {
private Logger logger = LoggerFactory.getLogger(FileDownloadServlet.class);
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 2822257745268393246L;

public void init() throws ServletException {
logger.info(FileDownloadServlet.class.getName() + " is inited.");
}

public void destroy() {
super.destroy();
}

/**
* 下载文件 已支持断点续传
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String base = "/download/";
String url = request.getRequestURI();
String path = url.substring(url.indexOf(base) + base.length());
path = URLDecoder.decode(path, "UTF-8");
// 获取文件对象信息
File file = new File(StringUtil.getFileTempReplace() + path);

if (!file.exists()) {
response.setStatus(404);
return;
}
BufferedInputStream bis = null;
try {
String fileName = file.getName();
long fileLength = file.length();
long start = 0, end = fileLength - 1, contentLength = fileLength;
String range = request.getHeader("Range");
if (range != null) {
// client requests a file block download start byte
String[] fromTo = range.split("=")[1].split("-");
start = Long.parseLong(fromTo[0]);
if (fromTo.length == 2 && fromTo[1] != null && !fromTo[1].equals(""))
end = Long.parseLong(fromTo[1]);
if (end >= fileLength)
end = fileLength - 1;
}
contentLength = end - start + 1;
// support multi-threaded download
// respone format:
// Content-Length:[file size] - [client request start bytes from
// file block]
// tell the client to allow accept-ranges
response.reset();
response.setHeader("Accept-Ranges", "bytes");
response.setContentLengthLong(contentLength);
// String contentType =
// Files.probeContentType(Paths.get(file.getPath()));
String contentType = request.getSession().getServletContext().getMimeType(fileName);
if (contentType == null && file.getPath().endsWith(".apk"))
contentType = "application/vnd.android.package-archive";
response.setContentType(contentType);
if (start > 0) {
response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
// 断点开始
// 响应的格式是:
// Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
String contentRange = new StringBuffer("bytes ").append(start).append("-").append(end).append("/")
.append(contentLength).toString();
response.setHeader("Content-Range", contentRange);
}
response.addHeader("Content-Disposition",
"attachment;filename=" + new String(fileName.getBytes("utf-8"), "ISO8859-1"));
// response.addHeader("Last-Modified:Mon", file.getvalue);
// get file content
byte[] buffer = new byte[4096];
int length = 0;
long count = 0;
OutputStream out = response.getOutputStream();
InputStream ins = new FileInputStream(file);
bis = new BufferedInputStream(ins);
if (start > 0) {
// pointer move to seek
bis.skip(start);
}
while ((length = bis.read(buffer)) != -1 && count < contentLength) {
out.write(buffer, 0, length);
count += length;
}
response.flushBuffer();

} catch (Exception ex) {
String msg = this.getClass().getName() + ".doGet() error: " + ex.toString();
logger.error(msg);
throw new ServletException(ex);
} finally {
if (bis != null)
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;
}
}


参考:http://www.oschina.net/code/snippet_182121_7941
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: