本篇文章給大家分享的是有關(guān)如何利用Java實(shí)現(xiàn)一個(gè)斷點(diǎn)續(xù)傳功能,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
我們提供的服務(wù)有:網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、廣德ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的廣德網(wǎng)站制作公司
功能實(shí)現(xiàn)的主要代碼:
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 * * 多線程的斷點(diǎn)下載程序,根據(jù)輸入的url和指定線程數(shù),來(lái)完成斷點(diǎn)續(xù)傳功能。 * * 每個(gè)線程支負(fù)責(zé)某一小段的數(shù)據(jù)下載;再通過(guò)RandomAccessFile完成數(shù)據(jù)的整合。 */ public class MultiTheradDownLoad { private String filepath = null; private String filename = null; private String tmpfilename = null; private int threadNum = 0; private CountDownLatch latch = null;//設(shè)置一個(gè)計(jì)數(shù)器,代碼內(nèi)主要用來(lái)完成對(duì)緩存文件的刪除 private long fileLength = 0l; private long threadLength = 0l; private long[] startPos;//保留每個(gè)線程下載數(shù)據(jù)的起始位置。 private long[] endPos;//保留每個(gè)線程下載數(shù)據(jù)的截止位置。 private boolean bool = false; private URL url = null; //有參構(gòu)造函數(shù),先構(gòu)造需要的數(shù)據(jù) 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); } /* * 組織斷點(diǎn)續(xù)傳功能的方法 */ public void downloadPart() { File file = null; File tmpfile = null; HttpURLConnection httpcon = null; //在請(qǐng)求url內(nèi)獲取文件資源的名稱;此處沒(méi)考慮文件名為空的情況,此種情況可能需使用UUID來(lái)生成一個(gè)唯一數(shù)來(lái)代表文件名。 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();//獲取請(qǐng)求資源的總長(zhǎng)度。 file = new File(filename); tmpfile = new File(tmpfilename); threadLength = fileLength / threadNum;//每個(gè)線程需下載的資源大小。 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();//當(dāng)你的計(jì)數(shù)器減為0之前,會(huì)在此處一直阻塞。 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(); } } } /* * 斷點(diǎn)設(shè)置方法,當(dāng)有臨時(shí)文件時(shí),直接在臨時(shí)文件中讀取上次下載中斷時(shí)的斷點(diǎn)位置。沒(méi)有臨時(shí)文件,即第一次下載時(shí),重新設(shè)置斷點(diǎn)。 * * rantmpfile.seek()跳轉(zhuǎn)到一個(gè)位置的目的是為了讓各個(gè)斷點(diǎn)存儲(chǔ)的位置盡量分開。 * * 這是實(shí)現(xiàn)斷點(diǎn)續(xù)傳的重要基礎(chǔ)。 */ 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"); //最后一個(gè)線程的截止位置大小為請(qǐng)求資源的大小 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(); } } } /* * 實(shí)現(xiàn)下載功能的內(nèi)部類,通過(guò)讀取斷點(diǎn)來(lái)設(shè)置向服務(wù)器請(qǐng)求的數(shù)據(jù)區(qū)間。 */ 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); //防止網(wǎng)絡(luò)阻塞,設(shè)置指定的超時(shí)時(shí)間;單位都是ms。超過(guò)指定時(shí)間,就會(huì)拋出異常 httpcon.setReadTimeout(20000);//讀取數(shù)據(jù)的超時(shí)設(shè)置 httpcon.setConnectTimeout(20000);//連接的超時(shí)設(shè)置 if (startPos < endPos) { //向服務(wù)器請(qǐng)求指定區(qū)間段的數(shù)據(jù),這是實(shí)現(xiàn)斷點(diǎn)續(xù)傳的根本。 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();//計(jì)數(shù)器自減 break; } is = httpcon.getInputStream();//獲取服務(wù)器返回的資源流 long count = 0l; byte[] buf = new byte[1024]; while (!this.task.bool && (length = is.read(buf)) != -1) { count += length; downloadfile.write(buf, 0, length); //不斷更新每個(gè)線程下載資源的起始位置,并寫入臨時(shí)文件;為斷點(diǎn)續(xù)傳做準(zhǔn)備 startPos += length; rantmpfile.seek(8 * id + 8); rantmpfile.writeLong(startPos); } System.out.println("the thread " + id + " total load count: " + count); //關(guān)閉流 is.close(); httpcon.disconnect(); downloadfile.close(); rantmpfile.close(); } latch.countDown();//計(jì)數(shù)器自減 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(); } } } } } /* * 為一個(gè)HttpURLConnection模擬請(qǐng)求頭,偽裝成一個(gè)瀏覽器發(fā)出的請(qǐng)求 */ 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"); } }
下面是測(cè)試代碼:
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(); } }
以上就是如何利用Java實(shí)現(xiàn)一個(gè)斷點(diǎn)續(xù)傳功能,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享名稱:如何利用Java實(shí)現(xiàn)一個(gè)斷點(diǎn)續(xù)傳功能
當(dāng)前路徑:http://aaarwkj.com/article6/pjccog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、ChatGPT、網(wǎng)站內(nèi)鏈、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)