簡易多執行緒下載
多執行緒斷點下載原理:
1.設定Range請求頭,開啟子執行緒後,各歸各下載相應的資料
2.下載的過程中,每個執行緒都有個檔案實時記錄當前下載進度,保證暫停下載後再次繼續可以獲取上次下載的進度。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
/**
*
* @author 多執行緒斷點下載
*
*/
public class ManyThreadDownload {
private static int threadTotalCount = 3; //總共開幾個執行緒執行
private static String path = "http://127.0.0.1:9090/555.exe"; //下載地址
private static int runningThreadCount; //當前正在執行的執行緒個數
public static void main(String[] args) {
HttpURLConnection conn = null;
try {
URL url = new URL(path); //URL地址
conn = (HttpURLConnection) url.openConnection(); //獲取一個連線物件
conn.setConnectTimeout(3000); //設定連線超時時間
conn.setReadTimeout(3000); //設定已經連上伺服器,但是在讀取資料時候的超時時間
conn.setRequestMethod("GET"); //設定請求方式
if (conn.getResponseCode() == 200) { //請求成功後
int size = conn.getContentLength(); //獲取伺服器返回的檔案大小
long blockSize = size / threadTotalCount; //每個執行緒要下載的大小=伺服器檔案大小/執行緒數
runningThreadCount = threadTotalCount; //剛開始的時候將執行緒總數賦值給正在執行的執行緒數
for (int i = 0; i < threadTotalCount; i++) { //迴圈開啟執行緒下載
long startIndex = i * blockSize; //計算每個執行緒開始位置下載的位置
long endIndex = (i + 1) * blockSize - 1; //計算每個執行緒結束位置下載的位置
if (i == (threadTotalCount - 1)) { //當迴圈到最後一個執行緒的時候,下載的結束位置就是檔案大總大小
endIndex = size;
}
new DownLoadThread(i, path, startIndex, endIndex).start();//進行下載
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
private static class DownLoadThread extends Thread {
private int threadIndex; //當前執行緒索引號
private String path; //下載檔案的url
private long startIndex; //開始下載的位置
private long endIndex; //下載到哪個位置結束
public DownLoadThread(int threadIndex, String path, long startIndex, long endIndex) {
this.threadIndex = threadIndex;
this.path = path;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
super.run();
HttpURLConnection conn = null;
File currentPositionFile = new File("Thread"+threadIndex+".txt"); //這個檔案是用於記錄每個執行緒下載進度的一個檔案,只儲存下載的位元組數
/* RandomAccessFile
* 用這個類來操作儲存下載進度的檔案,因為將這個類第二個引數設定rwd模式的話,會實時更新硬碟上的資料,而如果用FileOutputStream的話,就算呼叫flush,也只是刷到硬碟上的快取裡,
* 並沒有馬上寫到硬碟上
*/
RandomAccessFile currentPositionRAF = null;
int total = 0; //當前下載的位元組進度
try {
if(currentPositionFile.exists()&¤tPositionFile.length()>0){ //如果記錄進度的檔案存在的話,就表示之前暫停過
FileInputStream fis = new FileInputStream(currentPositionFile);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String lastPosition = br.readLine();
if(lastPosition!=null&&!"".equals(lastPosition.trim())){ //讀取進度檔案,如果讀到的內容不為空
total = Integer.parseInt(lastPosition); //將當前執行緒的總進度設定為進度檔案裡的進度
startIndex += Integer.valueOf(lastPosition); //將當前開始進度設定為進度檔案裡的進度(因為是斷點下載)
System.out.println("執行緒"+threadIndex+",從"+lastPosition+"繼續開始");
}
fis.close(); //千萬不要忘記關閉流
isr.close(); //千萬不要忘記關閉流
br.close(); //千萬不要忘記關閉流
}
URL url = new URL(path); //URL地址
conn = (HttpURLConnection) url.openConnection(); //獲取一個連線物件
conn.setConnectTimeout(3000); //設定連線超時時間
conn.setReadTimeout(3000); //設定已經連上伺服器,但是在讀取資料時候的超時時間
conn.setRequestMethod("GET"); //設定請求方式
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); //設定訊息頭是斷點下載,告訴伺服器返回指定片段資料
if(conn.getResponseCode()==206){ //帶著Range訊息頭去訪問伺服器,伺服器返回的狀態碼是206
InputStream is = conn.getInputStream(); //獲取伺服器返回資料的輸入流
File file = new File("hehe.exe"); //建立本地檔案
RandomAccessFile raf = new RandomAccessFile(file, "rw"); //建立一個往下載檔案裡寫資料的類
raf.seek(startIndex); //設定上次的進度
int len = 0;
byte[] buffer = new byte[1024*1024];
while((len=is.read(buffer))!=-1){
total += len;
currentPositionRAF = new RandomAccessFile(currentPositionFile, "rwd");
currentPositionRAF.write(String.valueOf(total).getBytes()); //寫進度
raf.write(buffer, 0, len);
//記錄檔案下載進度的txt檔案必須是迴圈裡寫一次關一次,因為JVM關閉的時候,不一定是迴圈完畢的時候,這時候進度檔案還是開啟著的
currentPositionRAF.close();
}
is.close();
raf.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
synchronized (ManyThreadDownload.class) {
if(conn!=null){
conn.disconnect();
}
//因為執行到finally時候,肯定是程式已經下載完畢了,所以把當前在執行的程式數減一
runningThreadCount--;
if(runningThreadCount==0){
for (int i = 0; i < threadTotalCount; i++) { //刪除記錄每個執行緒進度的臨時檔案
File file = new File("Thread"+i+".txt");
try {
System.out.println(file.delete());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
相關文章
- 簡易多執行緒爬蟲框架執行緒爬蟲框架
- Java簡單多執行緒斷點下載Java執行緒斷點
- Greendao多執行緒下載執行緒
- 多執行緒下的下載原理執行緒
- 多執行緒下載檔案執行緒
- Java多執行緒下載分析Java執行緒
- ftp多執行緒下載工具FTP執行緒
- 多執行緒下載工具 NeatDownloadManager下載執行緒
- Java多執行緒之Executor框架和手寫簡易的執行緒池Java執行緒框架
- 多執行緒下載原理解析執行緒
- 多執行緒斷點下載原理執行緒斷點
- Java多執行緒下載的例子。Java執行緒
- Chrome 開啟多執行緒下載Chrome執行緒
- Android 多執行緒下載,斷點續傳,執行緒池Android執行緒斷點
- 多執行緒簡易售票程式--孫鑫視訊示例執行緒
- Android原生下載(下篇)多檔案下載+多執行緒下載Android執行緒
- JAVA多執行緒下載的實現Java執行緒
- 實現FTP多執行緒下載 (轉)FTP執行緒
- https多執行緒下載程式碼HTTP執行緒
- 【Java】【多執行緒】執行緒池簡述Java執行緒
- C++簡易執行緒池C++執行緒
- 簡易執行緒池實現執行緒
- ObjC 多執行緒簡析(一)-多執行緒簡述和執行緒鎖的基本應用OBJ執行緒
- 強推!多執行緒下載工具 NeatDownloadManager執行緒
- Java多執行緒檔案分片下載實現Java執行緒
- 多執行緒下的list執行緒
- IOS下使用多執行緒iOS執行緒
- .NET下多執行緒初探執行緒
- 多執行緒下載nginx站點目錄下檔案執行緒Nginx
- 多執行緒和多執行緒同步執行緒
- 多執行緒Demo學習(執行緒的同步,簡單的執行緒通訊)執行緒
- 超強Mac多執行緒下載工具 NeatDownloadManager MacMac執行緒
- 網路程式設計基礎,多執行緒下載程式設計執行緒
- Chrome、Edge瀏覽器內建多執行緒下載Chrome瀏覽器執行緒
- 多執行緒【執行緒池】執行緒
- 多執行緒--執行緒管理執行緒
- Java多執行緒——執行緒Java執行緒
- 執行緒與多執行緒執行緒