Java 支持断点续传功能实现
2016-01-14 16:20
756 查看
服务器端代码:
客服端代码:
参考:http://www.oschina.net/code/snippet_182121_7941
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
相关文章推荐
- java实现获取当前日期所在的四个周的周日的功能,其中当前日期的周日是第三个,第四个是下周周日
- MyEclipse如何修改作者名称
- HDFS 抛出异常 (java.io.IOException: config())
- final finally finalize三者有什么区别
- Java关键字-final
- 如何解决 Java 安全问题?
- java:IO流学习小结
- spring-database_stats.xml
- Java编码问题汇总
- Spring事务配置的五种方式
- Maven 集成CXF Webservice,Spring
- java Comparator 与Comparable
- Java并发编程:Lock
- java 二进制上传文件
- [转]java static final 初始化
- Java并发编程:synchronized
- javaMail编写发送邮件的程序,以及遇到的问题
- java.sql.SQLSyntaxErrorException: ORA-00904: &quot;**&quot;: 标识符无效
- SAE部署Java应用
- Java clone() 浅克隆与深度克隆