1. 程式人生 > >java之斷點續傳簡單實現

java之斷點續傳簡單實現

斷點續傳主要是使用http協議中range的屬性來取得資源的部分內容,由於一般服務是不對外直接提供url訪問的,一般都是通過id,在servlet中輸出byte[]來實現,所以要想實現斷點續傳一般要自己實現服務端和客戶端,客戶端保持檔案的下載或上傳狀態,(儲存在本地或者資料庫中)。再進行中斷時保持中斷狀態,在進行續傳時,首先讀出檔案的狀態,然後設定range屬性資訊傳送續傳請求。伺服器收到續傳請求,讀取range屬性值,從檔案中讀取資料,傳送到客戶端。上述是基本的原理,上傳下載原理相同。

       下面模擬兩次從伺服器中現在檔案。

       客戶端:分多次取得部分檔案內容,利用RandomAccessFile檔案中讀取資料,寫到輸出流中。

  1. package org.nercita.zmx.servlet;  
  2. import java.io.FileNotFoundException;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.RandomAccessFile;  
  6. import java.net.HttpURLConnection;  
  7. import java.net.MalformedURLException;  
  8. import java.net.URL;  
  9. public class LoadClient {  
  10.     public static void load(int start, int end) throws MalformedURLException, FileNotFoundException{  
  11.         String endpoint = "http://localhost:8080/RestDemo/servlet/LoadServlet?id=5";  
  12.         URL url = new URL(endpoint);  
  13.         try {  
  14.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
  15.             conn.setRequestProperty("Content-Type","text/plain; charset=UTF-8");   
  16.             conn.setRequestProperty("RANGE","bytes="+start+"-"+end); //header中增加range屬性           
  17.             conn.connect();  
  18.             System.out.println(conn.getResponseCode());  
  19.             System.out.println(conn.getContentLength());  
  20.             System.out.println(conn.getContentType());  
  21.             InputStream ins = (InputStream)conn.getContent();     
  22.             String fileName=conn.getHeaderField("Content-Disposition");  
  23.             fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");  
  24.             fileName=fileName.substring(fileName.lastIndexOf("\\")+1);  
  25.             System.out.println(fileName);  
  26.             RandomAccessFile raFile = new RandomAccessFile("E:\\"+fileName, "rw");  
  27.             raFile.seek(start);           
  28.             byte[] buffer = new byte[4096];  
  29.             int len = -1;  
  30.             while((len = ins.read(buffer))!=-1){  
  31.                 raFile.write(buffer,0,len);  
  32.             }  
  33.             raFile.close();  
  34.             conn.disconnect();  
  35.         } catch (IOException e) {  
  36.             e.printStackTrace();  
  37.         }  
  38.     }  
  39.     public static void main(String[] args) throws IOException {  
  40.         load(0,1000);  
  41.         load(1001,0);  
  42.     }  
  43. }  


服務端:獲取分析range屬性,從收入流讀取內容位元組流,利用RandomAccessFile輸出到檔案中。其中還解決了中文檔名亂碼的問題,由於http協議中規定,當在網路中傳輸時,setHeader方法中的字元只能按ISO8859-1傳輸,所以這時候就要把Unicode字元轉換成了ISO8859-1的編碼傳到客戶端,客戶端進行解碼。否則會出現亂碼。

  1. package org.nercita.zmx.servlet;  
  2. import java.io.IOException;  
  3. import java.io.RandomAccessFile;  
  4. import javax.servlet.ServletException;  
  5. import javax.servlet.ServletOutputStream;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9. public class LoadServlet extends HttpServlet {  
  10.     private static final long serialVersionUID = 237208504975097723L;  
  11.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  12.             throws ServletException, IOException {  
  13.         int id = Integer.parseInt(request.getParameter("id"));  
  14.         System.out.println(request.getContextPath());  
  15.         String path = request.getServletContext().getRealPath("/load");  
  16.         String filename = "" ;  
  17.         if (id == 1)  
  18.             filename = path+"JDK_API_1_5_zh_CN.CHM";  
  19.         else if (id == 2)  
  20.             filename = path+"JDK_API_1_6_zh_CN.CHM";  
  21.         else if (id == 3)  
  22.             filename = path+"tomcat.gif";  
  23.         else  
  24.             filename = path+"\\斷點續傳text.txt";  
  25.         RandomAccessFile raFile = new RandomAccessFile(filename, "r");  
  26.         String range = request.getHeader("RANGE");  
  27.         int start=0end=0;  
  28.         if(null!=range && range.startsWith("bytes=")){  
  29.             String[] values =range.split("=")[1].split("-");  
  30.             start = Integer.parseInt(values[0]);  
  31.             end = Integer.parseInt(values[1]);  
  32.         }  
  33.         int requestSize=0;  
  34.         if(end!=0 && end > start){  
  35.             requestSize = end - start + 1;  
  36.             response.addHeader("content-length", ""+(requestSize));  
  37.         } else {  
  38.             requestSize = Integer.MAX_VALUE;  
  39.         }  
  40.         byte[] buffer = new byte[4096];           
  41.         response.setContentType("application/x-download");        
  42.         filename = new String(filename.getBytes("UTF-8"), "ISO8859-1");  
  43.         response.addHeader("Content-Disposition", "attachment;filename="+filename);  
  44.         ServletOutputStream os = response.getOutputStream();  
  45.         int needSize = requestSize;  
  46.         raFile.seek(start);  
  47.         while(needSize > 0){  
  48.             int len = raFile.read(buffer);  
  49.             if(needSize <buffer.length){  
  50.                 os.write(buffer,0,needSize);  
  51.             } else {  
  52.                 os.write(buffer,0,len);  
  53.                 if(len <buffer.length){  
  54.                     break;  
  55.                 }  
  56.             }  
  57.             needSize -buffer.length;  
  58.         }  
  59.         raFile.close();  
  60.         os.close();  
  61.     }  
  62.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  63.             throws ServletException, IOException {  
  64.          this.doGet(request, response);  
  65.     }  
  66. }  


             上述程式碼,已通過本人測試,有興趣的可以一試!