熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

用Java實現斷點續傳(HTTP)

2013-11-23 19:00:39  來源: Java核心技術 

  斷點續傳的原理

  其實斷點續傳的原理很簡單就是在 Http 的請求上和一般的下載有所不同而已

  打個比方浏覽器請求服務器上的一個文時所發出的請求如下

  假設服務器域名為 文件名為 downzip

  GET /downzip HTTP/

  Accept: image/gif image/xxbitmap image/jpeg image/pjpeg application/vndms

  excel application/msword application/vndmspowerpoint */*

  AcceptLanguage: zhcn

  AcceptEncoding: gzip deflate

  UserAgent: Mozilla/ (compatible; MSIE ; Windows NT )

  Connection: KeepAlive

  服務器收到請求後按要求尋找請求的文件提取文件的信息然後返回給浏覽器返回信息如下

  

  ContentLength=

  AcceptRanges=bytes

  Date=Mon Apr :: GMT

  ETag=W/caec:b

  ContentType=application/octetstream

  Server=MicrosoftIIS/

  LastModified=Mon Apr :: GMT

  所謂斷點續傳也就是要從文件已經下載的地方開始繼續下載所以在客戶端浏覽器傳給 Web 服務器的時候要多加一條信息 從哪裡開始

  下面是用自己編的一個浏覽器來傳遞請求信息給 Web 服務器要求從 字節開始

  GET /downzip HTTP/

  UserAgent: NetFox

  RANGE: bytes=

  Accept: text/html image/gif image/jpeg *; q= */*; q=

  仔細看一下就會發現多了一行 RANGE: bytes=

  這一行的意思就是告訴服務器 downzip 這個文件從 字節開始傳前面的字節不用傳了

  服務器收到這個請求以後返回的信息如下

  

  ContentLength=

  ContentRange=bytes /

  Date=Mon Apr :: GMT

  ETag=W/caec:b

  ContentType=application/octetstream

  Server=MicrosoftIIS/

  LastModified=Mon Apr :: GMT

  和前面服務器返回的信息比較一下就會發現增加了一行

  ContentRange=bytes /

  返回的代碼也改為 而不再是

  知道了以上原理就可以進行斷點續傳的編程了

  Java 實現斷點續傳的關鍵幾點

  () 用什麼方法實現提交 RANGE: bytes=

  當然用最原始的 Socket 是肯定能完成的不過那樣太費事了其實 Java 的 net 包中提供了這種功能代碼如下

  URL url = new URL();

  HttpURLConnection httpConnection = (HttpURLConnection)urlopenConnection();

  // 設置 UserAgent

  (UserAgentNetFox);

  // 設置斷點續傳的開始位置

  (RANGEbytes=);

  // 獲得輸入流

  InputStream input = ();

  從輸入流中取出的字節流就是 downzip 文件從 開始的字節流 大家看其實斷點續傳用 Java 實現起來還是很簡單的吧 接下來要做的事就是怎麼保存獲得的流到文件中去了

  保存文件采用的方法

  我采用的是 IO 包中的 RandAccessFile 類

  操作相當簡單假設從 處開始保存文件代碼如下

  RandomAccess oSavedFile = new RandomAccessFile(downziprw);

  long nPos = ;

  // 定位文件指針到 nPos 位置

  oSavedFileseek(nPos);

  byte[] b = new byte[];

  int nRead;

  // 從輸入流中讀入字節流然後寫到文件中

  while((nRead=inputread(b)) > )

  {

  oSavedFilewrite(bnRead);

  }

  怎麼樣也很簡單吧 接下來要做的就是整合成一個完整的程序了包括一系列的線程控制等等

  斷點續傳內核的實現

  主要用了 個類包括一個測試類

  SiteFileFetchjava 負責整個文件的抓取控制內部線程 (FileSplitterFetch 類 )

  FileSplitterFetchjava 負責部分文件的抓取

  FileAccessjava 負責文件的存儲

  SiteInfoBeanjava 要抓取的文件的信息如文件保存的目錄名字抓取文件的 URL 等

  Utilityjava 工具類放一些簡單的方法

  TestMethodjava 測試類

  下面是源程序

  /*

  /*

  * SiteFileFetchjava

  */

  package NetFox;

  import javaio*;

  import *;

  public class SiteFileFetch extends Thread {

  SiteInfoBean siteInfoBean = null; // 文件信息 Bean

  long[] nStartPos; // 開始位置

  long[] nEndPos; // 結束位置

  FileSplitterFetch[] fileSplitterFetch; // 子線程對象

  long nFileLength; // 文件長度

  boolean bFirst = true; // 是否第一次取文件

  boolean bStop = false; // 停止標志

  File tmpFile; // 文件下載的臨時信息

  DataOutputStream output; // 輸出到文件的輸出流

  public SiteFileFetch(SiteInfoBean bean) throws IOException

  {

  siteInfoBean = bean;

  //tmpFile = FilecreateTempFile (zhongnew File(beangetSFilePath()));

  tmpFile = new File(beangetSFilePath()+Fileseparator + beangetSFileName()+);

  if(tmpFileexists ())

  {

  bFirst = false;

  read_nPos();

  }

  else

  {

  nStartPos = new long[beangetNSplitter()];

  nEndPos = new long[beangetNSplitter()];

  }

  }

  public void run()

  {

  // 獲得文件長度

  // 分割文件

  // 實例 FileSplitterFetch

  // 啟動 FileSplitterFetch 線程

  // 等待子線程返回

  try{

  if(bFirst)

  {

  nFileLength = getFileSize();

  if(nFileLength == )

  {

  Systemerrprintln(File Length is not known!);

  }

  else if(nFileLength == )

  {

  Systemerrprintln(File is not access!);

  }

  else

  {

  for(int i=;i<nStartPoslength;i++)

  {

  nStartPos[i] = (long)(i*(nFileLength/nStartPoslength));

  }

  for(int i=;i<nEndPoslength;i++)

  {

  nEndPos[i] = nStartPos[i+];

  }

  nEndPos[nEndPoslength] = nFileLength;

  }

  }

  // 啟動子線程

  fileSplitterFetch = new FileSplitterFetch[nStartPoslength];

  for(int i=;i<nStartPoslength;i++)

  {

  fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBeangetSSiteURL()

  siteInfoBeangetSFilePath() + Fileseparator + siteInfoBeangetSFileName()

  nStartPos[i]nEndPos[i]i);

  Utilitylog(Thread + i + nStartPos = + nStartPos[i] + nEndPos =

  + nEndPos[i]);

  fileSplitterFetch[i]start();

  }

  // fileSplitterFetch[nPoslength] = new FileSplitterFetch(siteInfoBeangetSSiteURL()

  siteInfoBeangetSFilePath() + Fileseparator

  + siteInfoBeangetSFileName()nPos[nPoslength]nFileLengthnPoslength);

  // Utilitylog(Thread +(nPoslength) + nStartPos = +nPos[nPoslength]+

  nEndPos = + nFileLength);

  // fileSplitterFetch[nPoslength]start();

  // 等待子線程結束

  //int count = ;

  // 是否結束 while 循環

  boolean breakWhile = false;

  while(!bStop)

  {

  write_nPos();

  Utilitysleep();

  breakWhile = true;

  for(int i=;i<nStartPoslength;i++)

  {

  if(!fileSplitterFetch[i]bDownOver)

  {

  breakWhile = false;

  break;

  }

  }

  if(breakWhile)

  break;

  //count++;

  //if(count>)

  // siteStop();

  }

  Systemerrprintln(文件下載結束!);

  }

  catch(Exception e){eprintStackTrace ();}

  }

  // 獲得文件長度

  public long getFileSize()

  {

  int nFileLength = ;

  try{

  URL url = new URL(siteInfoBeangetSSiteURL());

  HttpURLConnection httpConnection = (HttpURLConnection)urlopenConnection ();

  (UserAgentNetFox);

  int responseCode=();

  if(responseCode>=)

  {

  processErrorCode(responseCode);

  return ; // represent access is error

  }

  String sHeader;

  for(int i=;;i++)

  {

  //DataInputStream in = new DataInputStream( ());

  //Utilitylog(inreadLine());

  sHeader=(i);

  if(sHeader!=null)

  {

  if(sHeaderequals(ContentLength))

  {

  nFileLength = IntegerparseInt((sHeader));

  break;

  }

  }

  else

  break;

  }

  }

  catch(IOException e){eprintStackTrace ();}

  catch(Exception e){eprintStackTrace ();}

  Utilitylog(nFileLength);

  return nFileLength;

  }

  // 保存下載信息(文件指針位置)

  private void write_nPos()

  {

  try{

  output = new DataOutputStream(new FileOutputStream(tmpFile));

  outputwriteInt(nStartPoslength);

  for(int i=;i<nStartPoslength;i++)

  {

  // outputwriteLong(nPos[i]);

  outputwriteLong(fileSplitterFetch[i]nStartPos);

  outputwriteLong(fileSplitterFetch[i]nEndPos);

  }

  outputclose();

  }

  catch(IOException e){eprintStackTrace ();}

  catch(Exception e){eprintStackTrace ();}

  }

  // 讀取保存的下載信息(文件指針位置)

  private void read_nPos()

  {

  try{

  DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));

  int nCount = inputreadInt();

  nStartPos = new long[nCount];

  nEndPos = new long[nCount];

  for(int i=;i<nStartPoslength;i++)

  {

  nStartPos[i] = inputreadLong();

  nEndPos[i] = inputreadLong();

  }

  inputclose();

  }

  catch(IOException e){eprintStackTrace ();}

  catch(Exception e){eprintStackTrace ();}

  }

  private void processErrorCode(int nErrorCode)

  {

  Systemerrprintln(Error Code : + nErrorCode);

  }

  // 停止文件下載

  public void siteStop()

  {

  bStop = true;

  for(int i=;i<nStartPoslength;i++)

  fileSplitterFetch[i]splitterStop();

  }

  }

  /*

  **FileSplitterFetchjava

  */

  package NetFox;

  import javaio*;

  import *;

  public class FileSplitterFetch extends Thread {

  String sURL; //File URL

  long nStartPos; //File Snippet Start Position

  long nEndPos; //File Snippet End Position

  int nThreadID; //Threads ID

  boolean bDownOver = false; //Downing is over

  boolean bStop = false; //Stop identical

  FileAccessI fileAccessI = null; //File Access interface

  public FileSplitterFetch(String sURLString sNamelong nStartlong nEndint id)

  throws IOException

  {

  thissURL = sURL;

  thisnStartPos = nStart;

  thisnEndPos = nEnd;

  nThreadID = id;

  fileAccessI = new FileAccessI(sNamenStartPos);

  }

  public void run()

  {

  while(nStartPos < nEndPos && !bStop)

  {

  try{

  URL url = new URL(sURL);

  HttpURLConnection httpConnection = (HttpURLConnection)urlopenConnection ();

  (UserAgentNetFox);

  String sProperty = bytes=+nStartPos+;

  (RANGEsProperty);

  Utilitylog(sProperty);

  InputStream input = ();

  //logResponseHead(httpConnection);

  byte[] b = new byte[];

  int nRead;

  while((nRead=inputread(b)) > && nStartPos < nEndPos

  && !bStop)

  {

  nStartPos += fileAccessIwrite(bnRead);

  //if(nThreadID == )

  // Utilitylog(nStartPos = + nStartPos + nEndPos = + nEndPos);

  }

  Utilitylog(Thread + nThreadID + is over!);

  bDownOver = true;

  //nPos = fileAccessIwrite (bnRead);

  }

  catch(Exception e){eprintStackTrace ();}

  }

  }

  // 打印回應的頭信息

  public void logResponseHead(HttpURLConnection con)

  {

  for(int i=;;i++)

  {

  String header=congetHeaderFieldKey(i);

  if(header!=null)

  //responseHeadersput(header(header));

  Utilitylog(header+ : +congetHeaderField(header));

  else

  break;

  }

  }

  public void splitterStop()

  {

  bStop = true;

  }

  }

  /*

  **FileAccessjava

  */

  package NetFox;

  import javaio*;

  public class FileAccessI implements Serializable{

  RandomAccessFile oSavedFile;

  long nPos;

  public FileAccessI() throws IOException

  {

  this();

  }

  public FileAccessI(String sNamelong nPos) throws IOException

  {

  oSavedFile = new RandomAccessFile(sNamerw);

  thisnPos = nPos;

  oSavedFileseek(nPos);

  }

  public synchronized int write(byte[] bint nStartint nLen)

  {

  int n = ;

  try{

  oSavedFilewrite(bnStartnLen);

  n = nLen;

  }

  catch(IOException e)

  {

  eprintStackTrace ();

  }

  return n;

  }

  }

  /*

  **SiteInfoBeanjava

  */

  package NetFox;

  public class SiteInfoBean {

  private String sSiteURL; //Sites URL

  private String sFilePath; //Saved Files Path

  private String sFileName; //Saved Files Name

  private int nSplitter; //Count of Splited Downloading File

  public SiteInfoBean()

  {

  //default value of nSplitter is

  this();

  }

  public SiteInfoBean(String sURLString sPathString sNameint nSpiltter)

  {

  sSiteURL= sURL;

  sFilePath = sPath;

  sFileName = sName;

  thisnSplitter = nSpiltter;

  }

  public String getSSiteURL()

  {

  return sSiteURL;

  }

  public void setSSiteURL(String value)

  {

  sSiteURL = value;

  }

  public String getSFilePath()

  {

  return sFilePath;

  }

  public void setSFilePath(String value)

  {

  sFilePath = value;

  }

  public String getSFileName()

  {

  return sFileName;

  }

  public void setSFileName(String value)

  {

  sFileName = value;

  }

  public int getNSplitter()

  {

  return nSplitter;

  }

  public void setNSplitter(int nCount)

  {

  nSplitter = nCount;

  }

  }

  /*

  **Utilityjava

  */

  package NetFox;

  public class Utility {

  public Utility()

  {

  }

  public static void sleep(int nSecond)

  {

  try{

  Threadsleep(nSecond);

  }

  catch(Exception e)

  {

  eprintStackTrace ();

  }

  }

  public static void log(String sMsg)

  {

  Systemerrprintln(sMsg);

  }

  public static void log(int sMsg)

  {

  Systemerrprintln(sMsg);

  }

  }

  /*

  **TestMethodjava

  */

  package NetFox;

  public class TestMethod {

  public TestMethod()

  { ///xx/weblogicb_winexe

  try{

  SiteInfoBean bean = new SiteInfoBean(

  L:\\tempweblogicb_winexe);

  //SiteInfoBean bean = new SiteInfoBean(L:\\temp

  weblogicb_winexe);

  SiteFileFetch fileFetch = new SiteFileFetch(bean);

  fileFetchstart();

  }

  catch(Exception e){eprintStackTrace ();}

  }

  public static void main(String[] args)

  {

  new TestMethod();

  }

  }


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26131.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.