国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java實現的斷點續傳功能

2019-11-14 23:26:47
字體:
來源:轉載
供稿:網友
java實現的斷點續傳功能

代碼中已經加入了注釋,需要的朋友可以直接參考代碼中的注釋。下面直接上功能實現的主要代碼:

import java.io.File;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;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/* * Encode:UTF-8 *  * Author:zhiming.xu *  * 多線程的斷點下載程序,根據輸入的url和指定線程數,來完成斷點續傳功能。 *  * 每個線程支負責某一小段的數據下載;再通過RandomAccessFile完成數據的整合。 */public class MultiTheradDownLoad {    PRivate String filepath = null;    private String filename = null;    private String tmpfilename = null;    private int threadNum = 0;    private CountDownLatch latch = null;//設置一個計數器,代碼內主要用來完成對緩存文件的刪除    private long fileLength = 0l;    private long threadLength = 0l;    private long[] startPos;//保留每個線程下載數據的起始位置。    private long[] endPos;//保留每個線程下載數據的截止位置。    private boolean bool = false;    private URL url = null;    //有參構造函數,先構造需要的數據    public MultiTheradDownLoad(String filepath, int threadNum) {        this.filepath = filepath;        this.threadNum = threadNum;        startPos = new long[this.threadNum];        endPos = new long[this.threadNum];        latch = new CountDownLatch(this.threadNum);    }    /*     * 組織斷點續傳功能的方法     */    public void downloadPart() {        File file = null;        File tmpfile = null;        HttpURLConnection httpcon = null;        //在請求url內獲取文件資源的名稱;此處沒考慮文件名為空的情況,此種情況可能需使用UUID來生成一個唯一數來代表文件名。        filename = filepath.substring(filepath.lastIndexOf('/') + 1, filepath                .contains("?") ? filepath.lastIndexOf('?') : filepath.length());        tmpfilename = filename + "_tmp";        try {            url = new URL(filepath);            httpcon = (HttpURLConnection) url.openConnection();            setHeader(httpcon);            fileLength = httpcon.getContentLengthLong();//獲取請求資源的總長度。            file = new File(filename);            tmpfile = new File(tmpfilename);            threadLength = fileLength / threadNum;//每個線程需下載的資源大小。            System.out.println("fileName: " + filename + " ," + "fileLength= "                    + fileLength + " the threadLength= " + threadLength);            if (file.exists() && file.length() == fileLength) {                System.out                        .println("the file you want to download has exited!!");                return;            } else {                setBreakPoint(startPos, endPos, tmpfile);                ExecutorService exec = Executors.newCachedThreadPool();                for (int i = 0; i < threadNum; i++) {                    exec.execute(new DownLoadThread(startPos[i], endPos[i],                            this, i, tmpfile, latch));                }                latch.await();//當你的計數器減為0之前,會在此處一直阻塞。                exec.shutdown();            }        } catch (MalformedURLException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } catch (InterruptedException e) {            e.printStackTrace();        }        if (file.length() == fileLength) {            if (tmpfile.exists()) {                System.out.println("delect the temp file!!");                tmpfile.delete();            }        }    }    /*     * 斷點設置方法,當有臨時文件時,直接在臨時文件中讀取上次下載中斷時的斷點位置。沒有臨時文件,即第一次下載時,重新設置斷點。     *      * rantmpfile.seek()跳轉到一個位置的目的是為了讓各個斷點存儲的位置盡量分開。     *      * 這是實現斷點續傳的重要基礎。     */    private void setBreakPoint(long[] startPos, long[] endPos, File tmpfile) {        RandomAccessFile rantmpfile = null;        try {            if (tmpfile.exists()) {                System.out.println("the download has continued!!");                rantmpfile = new RandomAccessFile(tmpfile, "rw");                for (int i = 0; i < threadNum; i++) {                    rantmpfile.seek(8 * i + 8);                    startPos[i] = rantmpfile.readLong();                    rantmpfile.seek(8 * (i + 1000) + 16);                    endPos[i] = rantmpfile.readLong();                    System.out.println("the Array content in the exit file: ");                    System.out.println("thre thread" + (i + 1) + " startPos:"                            + startPos[i] + ", endPos: " + endPos[i]);                }            } else {                System.out.println("the tmpfile is not available!!");                rantmpfile = new RandomAccessFile(tmpfile, "rw");                                //最后一個線程的截止位置大小為請求資源的大小                for (int i = 0; i < threadNum; i++) {                    startPos[i] = threadLength * i;                    if (i == threadNum - 1) {                        endPos[i] = fileLength;                    } else {                        endPos[i] = threadLength * (i + 1) - 1;                    }                    rantmpfile.seek(8 * i + 8);                    rantmpfile.writeLong(startPos[i]);                    rantmpfile.seek(8 * (i + 1000) + 16);                    rantmpfile.writeLong(endPos[i]);                    System.out.println("the Array content: ");                    System.out.println("thre thread" + (i + 1) + " startPos:"                            + startPos[i] + ", endPos: " + endPos[i]);                }            }        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                if (rantmpfile != null) {                    rantmpfile.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }    }        /*     * 實現下載功能的內部類,通過讀取斷點來設置向服務器請求的數據區間。     */    class DownLoadThread implements Runnable {        private long startPos;        private long endPos;        private MultiTheradDownLoad task = null;        private RandomAccessFile downloadfile = null;        private int id;        private File tmpfile = null;        private RandomAccessFile rantmpfile = null;        private CountDownLatch latch = null;        public DownLoadThread(long startPos, long endPos,                MultiTheradDownLoad task, int id, File tmpfile,                CountDownLatch latch) {            this.startPos = startPos;            this.endPos = endPos;            this.task = task;            this.tmpfile = tmpfile;            try {                this.downloadfile = new RandomAccessFile(this.task.filename,                        "rw");                this.rantmpfile = new RandomAccessFile(this.tmpfile, "rw");            } catch (FileNotFoundException e) {                e.printStackTrace();            }            this.id = id;            this.latch = latch;        }        @Override        public void run() {            HttpURLConnection httpcon = null;            InputStream is = null;            int length = 0;            System.out.println("the thread " + id + " has started!!");            while (true) {                try {                    httpcon = (HttpURLConnection) task.url.openConnection();                    setHeader(httpcon);                                        //防止網絡阻塞,設置指定的超時時間;單位都是ms。超過指定時間,就會拋出異常                    httpcon.setReadTimeout(20000);//讀取數據的超時設置                    httpcon.setConnectTimeout(20000);//連接的超時設置                    if (startPos < endPos) {                                                //向服務器請求指定區間段的數據,這是實現斷點續傳的根本。                        httpcon.setRequestProperty("Range", "bytes=" + startPos                                + "-" + endPos);                        System.out                                .println("Thread " + id                                        + " the total size:---- "                                        + (endPos - startPos));                        downloadfile.seek(startPos);                        if (httpcon.getResponseCode() != HttpURLConnection.HTTP_OK                                && httpcon.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {                            this.task.bool = true;                            httpcon.disconnect();                            downloadfile.close();                            System.out.println("the thread ---" + id                                    + " has done!!");                            latch.countDown();//計數器自減                            break;                        }                        is = httpcon.getInputStream();//獲取服務器返回的資源流                        long count = 0l;                        byte[] buf = new byte[1024];                        while (!this.task.bool && (length = is.read(buf)) != -1) {                            count += length;                            downloadfile.write(buf, 0, length);                                                        //不斷更新每個線程下載資源的起始位置,并寫入臨時文件;為斷點續傳做準備                            startPos += length;                            rantmpfile.seek(8 * id + 8);                            rantmpfile.writeLong(startPos);                        }                        System.out.println("the thread " + id                                + " total load count: " + count);                                                //關閉流                        is.close();                        httpcon.disconnect();                        downloadfile.close();                        rantmpfile.close();                    }                    latch.countDown();//計數器自減                    System.out.println("the thread " + id + " has done!!");                    break;                } catch (IOException e) {                    e.printStackTrace();                } finally {                    try {                        if (is != null) {                            is.close();                        }                    } catch (IOException e) {                        e.printStackTrace();                    }                }            }        }    }    /*     * 為一個HttpURLConnection模擬請求頭,偽裝成一個瀏覽器發出的請求     */    private void setHeader(HttpURLConnection con) {        con.setRequestProperty(                "User-Agent",                "Mozilla/5.0 (X11; U; linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3");        con.setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3");        con.setRequestProperty("Accept-Encoding", "aa");        con.setRequestProperty("Accept-Charset",                "ISO-8859-1,utf-8;q=0.7,*;q=0.7");        con.setRequestProperty("Keep-Alive", "300");        con.setRequestProperty("Connection", "keep-alive");        con.setRequestProperty("If-Modified-Since",                "Fri, 02 Jan 2009 17:00:05 GMT");        con.setRequestProperty("If-None-Match", "/"1261d8-4290-df64d224/"");        con.setRequestProperty("Cache-Control", "max-age=0");        con.setRequestProperty("Referer",                "http://www.skycn.com/soft/14857.html");    }}

下面是測試代碼:

public class DownLoadTest {    /**     * @param args     */    public static void main(String[] args) {                String filepath = "http://127.0.0.1:8080/file/loadfile.mkv";        MultiTheradDownLoad load = new MultiTheradDownLoad(filepath ,4);            load.downloadPart();        }}

參考資料:http://m.survivalescaperooms.com/topic/427397這篇文章對斷點續傳的原理做了較詳細的解釋。

代碼中還有多處可以優化的地方,這里就弄了。斷點續傳的原理其實很簡單,有興趣的朋友可以多多了解!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 枣强县| 卓尼县| 北票市| 怀化市| 江山市| 贵溪市| 南宁市| 广水市| 南城县| 攀枝花市| 社会| 阿勒泰市| 西贡区| 全州县| 石阡县| 江华| 靖州| 临汾市| 伊金霍洛旗| 台山市| 山阴县| 永泰县| 探索| 修水县| 乌什县| 瑞安市| 报价| 香港| 宜章县| 永康市| 武夷山市| 白沙| 邯郸市| 张家口市| 富平县| 陇西县| 乌什县| 梁山县| 南江县| 黄冈市| 屯留县|