<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Dict.CN 在線詞典, 英語學(xué)習(xí), 在線翻譯

    都市淘沙者

    荔枝FM Everyone can be host

    統(tǒng)計

    留言簿(23)

    積分與排名

    優(yōu)秀學(xué)習(xí)網(wǎng)站

    友情連接

    閱讀排行榜

    評論排行榜

    用Java實現(xiàn)斷點(diǎn)續(xù)傳(HTTP)

    本文介紹了一種利用 Java 來實現(xiàn)斷點(diǎn)續(xù)傳的方法。

    斷點(diǎn)續(xù)傳的原理 原文http://www.ibm.com/developerworks/cn/java/joy-down/index.html

    其實斷點(diǎn)續(xù)傳的原理很簡單,就是在Http的請求上和一般的下載有所不同而已。
    打個比方,瀏覽器請求服務(wù)器上的一個文時,所發(fā)出的請求如下:
    假設(shè)服務(wù)器域名為wwww.sjtu.edu.cn,文件名為down.zip。
    GET /down.zip HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
    excel, application/msword, application/vnd.ms-powerpoint, */*
    Accept-Language: zh-cn
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
    Connection: Keep-Alive

    服務(wù)器收到請求后,按要求尋找請求的文件,提取文件的信息,然后返回給瀏覽器,返回信息如下:

    200
    Content-Length=106786028
    Accept-Ranges=bytes
    Date=Mon, 30 Apr 2001 12:56:11 GMT
    ETag=W/"02ca57e173c11:95b"
    Content-Type=application/octet-stream
    Server=Microsoft-IIS/5.0
    Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT

    所謂斷點(diǎn)續(xù)傳,也就是要從文件已經(jīng)下載的地方開始繼續(xù)下載。所以在客戶端瀏覽器傳給 Web服務(wù)器的時候要多加一條信息--從哪里開始。
    下面是用自己編的一個"瀏覽器"來傳遞請求信息給Web服務(wù)器,要求從2000070字節(jié)開始。
    GET /down.zip HTTP/1.0
    User-Agent: NetFox
    RANGE: bytes=2000070-
    Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

    仔細(xì)看一下就會發(fā)現(xiàn)多了一行RANGE: bytes=2000070-
    這一行的意思就是告訴服務(wù)器down.zip這個文件從2000070字節(jié)開始傳,前面的字節(jié)不用傳了。
    服務(wù)器收到這個請求以后,返回的信息如下:
    206
    Content-Length=106786028
    Content-Range=bytes 2000070-106786027/106786028
    Date=Mon, 30 Apr 2001 12:55:20 GMT
    ETag=W/"02ca57e173c11:95b"
    Content-Type=application/octet-stream
    Server=Microsoft-IIS/5.0
    Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

    和前面服務(wù)器返回的信息比較一下,就會發(fā)現(xiàn)增加了一行:
    Content-Range=bytes 2000070-106786027/106786028
    返回的代碼也改為206了,而不再是200了。

    知道了以上原理,就可以進(jìn)行斷點(diǎn)續(xù)傳的編程了。





    回頁首


    Java實現(xiàn)斷點(diǎn)續(xù)傳的關(guān)鍵幾點(diǎn)

    1. (1)用什么方法實現(xiàn)提交RANGE: bytes=2000070-。
      當(dāng)然用最原始的Socket是肯定能完成的,不過那樣太費(fèi)事了,其實Java的net包中提供了這種功能。代碼如下:

      URL url = new URL("http://www.sjtu.edu.cn/down.zip");
      HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();

      //設(shè)置User-Agent
      httpConnection.setRequestProperty("User-Agent","NetFox");
      //設(shè)置斷點(diǎn)續(xù)傳的開始位置
      httpConnection.setRequestProperty("RANGE","bytes=2000070");
      //獲得輸入流
      InputStream input = httpConnection.getInputStream();

      從輸入流中取出的字節(jié)流就是down.zip文件從2000070開始的字節(jié)流。大家看,其實斷點(diǎn)續(xù)傳用Java實現(xiàn)起來還是很簡單的吧。接下來要做的事就是怎么保存獲得的流到文件中去了。

    2. 保存文件采用的方法。
      我采用的是IO包中的RandAccessFile類。
      操作相當(dāng)簡單,假設(shè)從2000070處開始保存文件,代碼如下:
      RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");
      long nPos = 2000070;
      //定位文件指針到nPos位置
      oSavedFile.seek(nPos);
      byte[] b = new byte[1024];
      int nRead;
      //從輸入流中讀入字節(jié)流,然后寫到文件中
      while((nRead=input.read(b,0,1024)) > 0)
      {
      oSavedFile.write(b,0,nRead);
      }

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





    回頁首


    斷點(diǎn)續(xù)傳內(nèi)核的實現(xiàn)

    主要用了6個類,包括一個測試類。
    SiteFileFetch.java負(fù)責(zé)整個文件的抓取,控制內(nèi)部線程(FileSplitterFetch類)。
    FileSplitterFetch.java負(fù)責(zé)部分文件的抓取。
    FileAccess.java負(fù)責(zé)文件的存儲。
    SiteInfoBean.java要抓取的文件的信息,如文件保存的目錄,名字,抓取文件的URL等。
    Utility.java工具類,放一些簡單的方法。
    TestMethod.java測試類。

    下面是源程序:

    /*
                **SiteFileFetch.java
                */
                package NetFox;
                import java.io.*;
                import java.net.*;
                public class SiteFileFetch extends Thread {
                SiteInfoBean siteInfoBean = null; //文件信息Bean
                long[] nStartPos; //開始位置
                long[] nEndPos; //結(jié)束位置
                FileSplitterFetch[] fileSplitterFetch; //子線程對象
                long nFileLength; //文件長度
                boolean bFirst = true; //是否第一次取文件
                boolean bStop = false; //停止標(biāo)志
                File tmpFile; //文件下載的臨時信息
                DataOutputStream output; //輸出到文件的輸出流
                public SiteFileFetch(SiteInfoBean bean) throws IOException
                {
                siteInfoBean = bean;
                //tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath()));
                tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");
                if(tmpFile.exists ())
                {
                bFirst = false;
                read_nPos();
                }
                else
                {
                nStartPos = new long[bean.getNSplitter()];
                nEndPos = new long[bean.getNSplitter()];
                }
                }
                public void run()
                {
                //獲得文件長度
                //分割文件
                //實例FileSplitterFetch
                //啟動FileSplitterFetch線程
                //等待子線程返回
                try{
                if(bFirst)
                {
                nFileLength = getFileSize();
                if(nFileLength == -1)
                {
                System.err.println("File Length is not known!");
                }
                else if(nFileLength == -2)
                {
                System.err.println("File is not access!");
                }
                else
                {
                for(int i=0;i<nStartPos.length;i++)
                {
                nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));
                }
                for(int i=0;i<nEndPos.length-1;i++)
                {
                nEndPos[i] = nStartPos[i+1];
                }
                nEndPos[nEndPos.length-1] = nFileLength;
                }
                }
                //啟動子線程
                fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
                for(int i=0;i<nStartPos.length;i++)
                {
                fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
                siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),
                nStartPos[i],nEndPos[i],i);
                Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);
                fileSplitterFetch[i].start();
                }
                // fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
                siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);
                // Utility.log("Thread " + (nPos.length-1) + " , nStartPos = " + nPos[nPos.length-1] + ",
                nEndPos = " + nFileLength);
                // fileSplitterFetch[nPos.length-1].start();
                //等待子線程結(jié)束
                //int count = 0;
                //是否結(jié)束while循環(huán)
                boolean breakWhile = false;
                while(!bStop)
                {
                write_nPos();
                Utility.sleep(500);
                breakWhile = true;
                for(int i=0;i<nStartPos.length;i++)
                {
                if(!fileSplitterFetch[i].bDownOver)
                {
                breakWhile = false;
                break;
                }
                }
                if(breakWhile)
                break;
                //count++;
                //if(count>4)
                // siteStop();
                }
                System.err.println("文件下載結(jié)束!");
                }
                catch(Exception e){e.printStackTrace ();}
                }
                //獲得文件長度
                public long getFileSize()
                {
                int nFileLength = -1;
                try{
                URL url = new URL(siteInfoBean.getSSiteURL());
                HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
                httpConnection.setRequestProperty("User-Agent","NetFox");
                int responseCode=httpConnection.getResponseCode();
                if(responseCode>=400)
                {
                processErrorCode(responseCode);
                return -2; //-2 represent access is error
                }
                String sHeader;
                for(int i=1;;i++)
                {
                //DataInputStream in = new DataInputStream(httpConnection.getInputStream ());
                //Utility.log(in.readLine());
                sHeader=httpConnection.getHeaderFieldKey(i);
                if(sHeader!=null)
                {
                if(sHeader.equals("Content-Length"))
                {
                nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
                break;
                }
                }
                else
                break;
                }
                }
                catch(IOException e){e.printStackTrace ();}
                catch(Exception e){e.printStackTrace ();}
                Utility.log(nFileLength);
                return nFileLength;
                }
                //保存下載信息(文件指針位置)
                private void write_nPos()
                {
                try{
                output = new DataOutputStream(new FileOutputStream(tmpFile));
                output.writeInt(nStartPos.length);
                for(int i=0;i<nStartPos.length;i++)
                {
                // output.writeLong(nPos[i]);
                output.writeLong(fileSplitterFetch[i].nStartPos);
                output.writeLong(fileSplitterFetch[i].nEndPos);
                }
                output.close();
                }
                catch(IOException e){e.printStackTrace ();}
                catch(Exception e){e.printStackTrace ();}
                }
                //讀取保存的下載信息(文件指針位置)
                private void read_nPos()
                {
                try{
                DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));
                int nCount = input.readInt();
                nStartPos = new long[nCount];
                nEndPos = new long[nCount];
                for(int i=0;i<nStartPos.length;i++)
                {
                nStartPos[i] = input.readLong();
                nEndPos[i] = input.readLong();
                }
                input.close();
                }
                catch(IOException e){e.printStackTrace ();}
                catch(Exception e){e.printStackTrace ();}
                }
                private void processErrorCode(int nErrorCode)
                {
                System.err.println("Error Code : " + nErrorCode);
                }
                //停止文件下載
                public void siteStop()
                {
                bStop = true;
                for(int i=0;i<nStartPos.length;i++)
                fileSplitterFetch[i].splitterStop();
                }
                }
                /*
                **FileSplitterFetch.java
                */
                package NetFox;
                import java.io.*;
                import java.net.*;
                public class FileSplitterFetch extends Thread {
                String sURL; //File URL
                long nStartPos; //File Snippet Start Position
                long nEndPos; //File Snippet End Position
                int nThreadID; //Thread's ID
                boolean bDownOver = false; //Downing is over
                boolean bStop = false; //Stop identical
                FileAccessI fileAccessI = null; //File Access interface
                public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException
                {
                this.sURL = sURL;
                this.nStartPos = nStart;
                this.nEndPos = nEnd;
                nThreadID = id;
                fileAccessI = new FileAccessI(sName,nStartPos);
                }
                public void run()
                {
                while(nStartPos < nEndPos && !bStop)
                {
                try{
                URL url = new URL(sURL);
                HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
                httpConnection.setRequestProperty("User-Agent","NetFox");
                String sProperty = "bytes="+nStartPos+"-";
                httpConnection.setRequestProperty("RANGE",sProperty);
                Utility.log(sProperty);
                InputStream input = httpConnection.getInputStream();
                //logResponseHead(httpConnection);
                byte[] b = new byte[1024];
                int nRead;
                while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos && !bStop)
                {
                nStartPos += fileAccessI.write(b,0,nRead);
                //if(nThreadID == 1)
                // Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);
                }
                Utility.log("Thread " + nThreadID + " is over!");
                bDownOver = true;
                //nPos = fileAccessI.write (b,0,nRead);
                }
                catch(Exception e){e.printStackTrace ();}
                }
                }
                //打印回應(yīng)的頭信息
                public void logResponseHead(HttpURLConnection con)
                {
                for(int i=1;;i++)
                {
                String header=con.getHeaderFieldKey(i);
                if(header!=null)
                //responseHeaders.put(header,httpConnection.getHeaderField(header));
                Utility.log(header+" : "+con.getHeaderField(header));
                else
                break;
                }
                }
                public void splitterStop()
                {
                bStop = true;
                }
                }
                /*
                **FileAccess.java
                */
                package NetFox;
                import java.io.*;
                public class FileAccessI implements Serializable{
                RandomAccessFile oSavedFile;
                long nPos;
                public FileAccessI() throws IOException
                {
                this("",0);
                }
                public FileAccessI(String sName,long nPos) throws IOException
                {
                oSavedFile = new RandomAccessFile(sName,"rw");
                this.nPos = nPos;
                oSavedFile.seek(nPos);
                }
                public synchronized int write(byte[] b,int nStart,int nLen)
                {
                int n = -1;
                try{
                oSavedFile.write(b,nStart,nLen);
                n = nLen;
                }
                catch(IOException e)
                {
                e.printStackTrace ();
                }
                return n;
                }
                }
                /*
                **SiteInfoBean.java
                */
                package NetFox;
                public class SiteInfoBean {
                private String sSiteURL; //Site's URL
                private String sFilePath; //Saved File's Path
                private String sFileName; //Saved File's Name
                private int nSplitter; //Count of Splited Downloading File
                public SiteInfoBean()
                {
                //default value of nSplitter is 5
                this("","","",5);
                }
                public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter)
                {
                sSiteURL= sURL;
                sFilePath = sPath;
                sFileName = sName;
                this.nSplitter = 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;
                }
                }
                /*
                **Utility.java
                */
                package NetFox;
                public class Utility {
                public Utility()
                {
                }
                public static void sleep(int nSecond)
                {
                try{
                Thread.sleep(nSecond);
                }
                catch(Exception e)
                {
                e.printStackTrace ();
                }
                }
                public static void log(String sMsg)
                {
                System.err.println(sMsg);
                }
                public static void log(int sMsg)
                {
                System.err.println(sMsg);
                }
                }
                /*
                **TestMethod.java
                */
                package NetFox;
                public class TestMethod {
                public TestMethod()
                { ///xx/weblogic60b2_win.exe
                try{
                SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe","L:\\temp","weblogic60b2_win.exe",5);
                //SiteInfoBean bean = new SiteInfoBean("http://localhost:8080/down.zip","L:\\temp","weblogic60b2_win.exe",5);
                SiteFileFetch fileFetch = new SiteFileFetch(bean);
                fileFetch.start();
                }
                catch(Exception e){e.printStackTrace ();}
                }
                public static void main(String[] args)
                {
                new TestMethod();
                }
                }
                

    posted on 2008-05-16 11:12 都市淘沙者 閱讀(523) 評論(0)  編輯  收藏 所屬分類: 流媒體服務(wù)器/VLC/FFmpeg

    主站蜘蛛池模板: 在线a亚洲v天堂网2018| 亚洲a级成人片在线观看| 亚洲AV无码无限在线观看不卡| 99精品免费视频| 亚洲网红精品大秀在线观看| 亚洲国产精品成人午夜在线观看| 四虎影视永久免费观看| 亚洲一区二区久久| 国产一区二区三区在线免费观看| 成人免费777777被爆出| 国产成人精品亚洲日本在线| 国产成人精品久久亚洲| 日韩在线观看免费| 国产高清在线免费视频| 亚洲精华国产精华精华液好用| 在线A亚洲老鸭窝天堂| 亚洲精品视频免费在线观看| 高清免费久久午夜精品 | 永久黄网站色视频免费| sss日本免费完整版在线观看| www.91亚洲| 美丽的姑娘免费观看在线播放 | 一级毛片成人免费看免费不卡 | 亚洲中字慕日产2020| 亚洲毛片不卡av在线播放一区| 亚洲视频在线免费播放| 一区二区三区视频免费观看| 亚洲婷婷五月综合狠狠爱| 青苹果乐园免费高清在线| 免费看少妇高潮成人片| 亚洲国产精品久久久久婷婷软件| 最近2019年免费中文字幕高清| 免费激情网站国产高清第一页| 在线亚洲97se亚洲综合在线| 日本免费网站在线观看| 丁香六月婷婷精品免费观看| 亚洲а∨天堂久久精品9966| 亚洲AV日韩AV天堂久久| 亚洲爽爽一区二区三区| 日韩免费毛片视频| 免费精品国产自产拍在线观看图片|