java多線程下載服務器資源文件-------(demo)支持斷點下載

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;

public class Main {
	// 設置線程的數量爲3
	private final static int THRED_COUNT = 3;
	final static String path = "http://188.188.7.85/kugou.exe";

	public static void main(String[] args) {
		
	System.out.println(getFilename());

		// 創建三個線程進行多線程的下載資源文件
		try {
			URL url = new URL(path);
			// 1.獲取文件資源的連接
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// 2.獲取服務器資源文件的大小
			int length = conn.getContentLength();
			
			//3.在本地生成與之一樣的文件,使用隨機流
			RandomAccessFile raf = new RandomAccessFile(getFilename(), "rw");
			//設置文件的長度
			raf.setLength(length);
			
			//4.開始劃分每一個線程從什麼位置下載到什麼位置
			int blockSize = length  / THRED_COUNT;

			//5.開啓3個線程進行下載
			
			for (int threadId = 0; threadId < THRED_COUNT; threadId++) {
				
				//每個線程的下載開始位置
				int startIndex = threadId*blockSize;
				
				//線程下載的結束位置
				int endIndex = (threadId + 1 )*blockSize -1;
				
				//如果是最後一個線程,讓這個線程執行後面剩餘的文字資源
				if(threadId == THRED_COUNT){
					endIndex = length - 1;
				}
				
				//開始線程去下載,並傳遞進去每一個線程下載的起始位置
				
				new Downloader(threadId,startIndex,endIndex).start();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//獲取路徑中的文件名
	private static String getFilename(){
		
		return path.substring(path.lastIndexOf("/")+1);
	}
	
	//下載的線程
	static class Downloader extends Thread{
		private int startIndex;
		private int endIndex;
		private int threadId;
		private int currentPosition;
		public Downloader(int threadId,int startIndex,int endIndex) {
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
			currentPosition = startIndex;
			System.out.println("線程"+threadId+"-下載的位置從:" + startIndex+" ---"+endIndex);
		}
		
		@Override
		public void run() {
			try{
				//先找到之前記錄好的位置信息
				File  file = new File(threadId+".position");
				
				//判斷以前曾經下載過文件,這個時候必須讀取裏裏面的位置信息  
				//(斷點下載的方式:就是記錄每次下載之後的位置,並實時保存到硬盤中,所以使用到了隨機流進行實時寫出斷點下載的位置文件信息)
				if(file.exists() && file.length()>0){
					FileInputStream fis = new FileInputStream(file);
					BufferedReader bReader = new BufferedReader(new InputStreamReader(fis));
					//讀取線程曾經下載到的位置
					currentPosition = Integer.parseInt(bReader.readLine());
					System.out.println("以前有下載過文件--"+threadId +"--從"+currentPosition+"開始下載");
					bReader.close();
					fis.close();
					
				}else{
					System.out.println("以前沒有下載過文件,從頭開始下載------");
				}
				
				URL url = new URL(path);
				
				HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
				//conn.getInputStream()//獲取這個資源對應的所有輸入流
				//爲了實現每一線程下載的東西都是固有的位置,所以必須告訴服務器,每一個線程從什麼位置開始下載
				
				//設置線程下載資源的位置
				conn.setRequestProperty("Range", "bytes:"+currentPosition+"-"+endIndex);
				
				//獲取線程訪問返回的狀態碼    線程下載返回的是206
				int code = conn.getResponseCode();
				
				if(206 == code){
					InputStream in = conn.getInputStream();
					//寫文件的時候要注意,因爲已經規定了每一個線程從什麼位置開始下載,所以
					//寫數據的時候必須從指定位置開始寫入
					RandomAccessFile raf = new RandomAccessFile(getFilename(), "rw");
					raf.seek(currentPosition);
					
					
					byte[] buffer = new byte[1024];
					int len = 0;
					while((len = in.read(buffer)) != -1){
						raf.write(buffer,0,len);
						
						//這幾必須寫在上面這句語句後面,不然會數據混亂問題出現問題
						currentPosition  += len;
						
						//必須使用隨機流進行讀寫現在下載位置的配置信息,不然會出現各種問題,(主要是硬盤的緩存問題)
						RandomAccessFile fos= new RandomAccessFile(threadId+".position", "rwd");
						fos.write((currentPosition+"").getBytes());
						fos.close();
					}
					System.out.println("線程"+threadId+"--已經下載結束了。。");
					//下載完成之後,要刪除(斷點下載的配置文件.position)
					//如果存在斷點配置.position文件,將其刪除
					file.delete();
					
					raf.close();
					in.close();
					
					
				}
				
				
			}catch (Exception e) {
				e.printStackTrace();
			}

		}
		
		
		
	}
}

一.注意:多線程下載資源文件是爲了提高效率(比如:迅雷下載)

斷點下載的原理:每次讀取到的文件都將其的位置寫入配置文件中


下面是一個Demo:





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章