java之斷點續傳簡單實現
阿新 • • 發佈:2019-01-03
斷點續傳主要是使用http協議中range的屬性來取得資源的部分內容,由於一般服務是不對外直接提供url訪問的,一般都是通過id,在servlet中輸出byte[]來實現,所以要想實現斷點續傳一般要自己實現服務端和客戶端,客戶端保持檔案的下載或上傳狀態,(儲存在本地或者資料庫中)。再進行中斷時保持中斷狀態,在進行續傳時,首先讀出檔案的狀態,然後設定range屬性資訊傳送續傳請求。伺服器收到續傳請求,讀取range屬性值,從檔案中讀取資料,傳送到客戶端。上述是基本的原理,上傳下載原理相同。
下面模擬兩次從伺服器中現在檔案。
客戶端:分多次取得部分檔案內容,利用RandomAccessFile檔案中讀取資料,寫到輸出流中。
- package org.nercita.zmx.servlet;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.RandomAccessFile;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.URL;
-
public class LoadClient {
- public static void load(int start, int end) throws MalformedURLException, FileNotFoundException{
- String endpoint = "http://localhost:8080/RestDemo/servlet/LoadServlet?id=5";
- URL url = new URL(endpoint);
- try {
-
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestProperty("Content-Type","text/plain; charset=UTF-8");
- conn.setRequestProperty("RANGE","bytes="+start+"-"+end); //header中增加range屬性
- conn.connect();
- System.out.println(conn.getResponseCode());
- System.out.println(conn.getContentLength());
- System.out.println(conn.getContentType());
- InputStream ins = (InputStream)conn.getContent();
- String fileName=conn.getHeaderField("Content-Disposition");
- fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");
- fileName=fileName.substring(fileName.lastIndexOf("\\")+1);
- System.out.println(fileName);
- RandomAccessFile raFile = new RandomAccessFile("E:\\"+fileName, "rw");
- raFile.seek(start);
- byte[] buffer = new byte[4096];
- int len = -1;
- while((len = ins.read(buffer))!=-1){
- raFile.write(buffer,0,len);
- }
- raFile.close();
- conn.disconnect();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) throws IOException {
- load(0,1000);
- load(1001,0);
- }
- }
服務端:獲取分析range屬性,從收入流讀取內容位元組流,利用RandomAccessFile輸出到檔案中。其中還解決了中文檔名亂碼的問題,由於http協議中規定,當在網路中傳輸時,setHeader方法中的字元只能按ISO8859-1傳輸,所以這時候就要把Unicode字元轉換成了ISO8859-1的編碼傳到客戶端,客戶端進行解碼。否則會出現亂碼。
- package org.nercita.zmx.servlet;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import javax.servlet.ServletException;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class LoadServlet extends HttpServlet {
- private static final long serialVersionUID = 237208504975097723L;
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- int id = Integer.parseInt(request.getParameter("id"));
- System.out.println(request.getContextPath());
- String path = request.getServletContext().getRealPath("/load");
- String filename = "" ;
- if (id == 1)
- filename = path+"JDK_API_1_5_zh_CN.CHM";
- else if (id == 2)
- filename = path+"JDK_API_1_6_zh_CN.CHM";
- else if (id == 3)
- filename = path+"tomcat.gif";
- else
- filename = path+"\\斷點續傳text.txt";
- RandomAccessFile raFile = new RandomAccessFile(filename, "r");
- String range = request.getHeader("RANGE");
- int start=0, end=0;
- if(null!=range && range.startsWith("bytes=")){
- String[] values =range.split("=")[1].split("-");
- start = Integer.parseInt(values[0]);
- end = Integer.parseInt(values[1]);
- }
- int requestSize=0;
- if(end!=0 && end > start){
- requestSize = end - start + 1;
- response.addHeader("content-length", ""+(requestSize));
- } else {
- requestSize = Integer.MAX_VALUE;
- }
- byte[] buffer = new byte[4096];
- response.setContentType("application/x-download");
- filename = new String(filename.getBytes("UTF-8"), "ISO8859-1");
- response.addHeader("Content-Disposition", "attachment;filename="+filename);
- ServletOutputStream os = response.getOutputStream();
- int needSize = requestSize;
- raFile.seek(start);
- while(needSize > 0){
- int len = raFile.read(buffer);
- if(needSize <buffer.length){
- os.write(buffer,0,needSize);
- } else {
- os.write(buffer,0,len);
- if(len <buffer.length){
- break;
- }
- }
- needSize -= buffer.length;
- }
- raFile.close();
- os.close();
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- this.doGet(request, response);
- }
- }
上述程式碼,已通過本人測試,有興趣的可以一試!