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

java中http斷點續傳的原理(1)

2013-11-23 19:29:52  來源: 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 ();}

  }


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26964.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.