溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在java中利用多線程實現文件下載

發布時間:2021-05-27 17:58:34 來源:億速云 閱讀:222 作者:Leah 欄目:編程語言

怎么在java中利用多線程實現文件下載?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

1、DownloadManager類

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
 
public class DownloadManager implements Runnable {
 // 保存路徑
 private String savePath;
 // 總的下載線程數
 private int threadNum;
 // 下載的鏈接地址
 private String urlFile;
 // 是否下載開始
 private boolean isStarted;
 // 用于監視何時合并文件存放Thread的list
 private List<DownloadThread> downloadList = new ArrayList<DownloadThread>();
 
 public DownloadManager(String savePath, int threadNum, String urlFile) {
 super();
 this.savePath = savePath;
 this.threadNum = threadNum;
 this.urlFile = urlFile;
 }
 
 // 最終調用線程下載。本線程中調用分線程。
 public void action() {
 new Thread(this).start();
 }
 
 public void run() {
 long t1 = System.currentTimeMillis();
 System.out.println(t1);
 // 如果沒有下載 , 就開始 , 并且將已經下載的變量值設為true
 if (!isStarted) {
 startDownload();
 isStarted = true;
 }
 while (true) {
 // 初始化認為所有線程下載完成,逐個檢查
 boolean finish = true;
 // 如果有任何一個沒完成,說明下載沒完成,不能合并文件
 for (DownloadThread thread : downloadList) {
 if (!thread.isFinish()) {
 finish = false;
 break;
 }
 }
 // 全部下載完成才為真
 if (finish) {
 // 合并文件
 mergeFiles();
 // 跳出循環 , 下載結束
 break;
 }
 // 休息一會 , 減少cpu消耗
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 long t2 = System.currentTimeMillis();
 System.out.println(t2);
 System.out.println("下載用時:" + (t2 -t1));
 }
 
 public void startDownload() {
 // 得到每個線程開始值 , 下載字節數大小
 int[][] posAndLength = getPosAndLength();
 // 根據下載信息創建每個下載線程,并且啟動他們。
 for (int i = 0; i < posAndLength.length; i++) {
 int pos = posAndLength[i][0];
 int length = posAndLength[i][1];
 DownloadThread downloadThread = new DownloadThread(i + 1, length,
 pos, savePath, urlFile);
 new Thread(downloadThread).start();
 downloadList.add(downloadThread);
 }
 }
 
 /**
 * 獲得文件大小
 * 
 * @return 文件大小
 */
 public long getFileLength() {
 System.out.println("獲得文件大小 start......");
 HttpURLConnection conn = null;
 long result = 0;
 try {
 URL url = new URL(urlFile);
 conn = (HttpURLConnection) url.openConnection();
 // 使用Content-Length頭信息獲得文件大小
 result = Long.parseLong(conn.getHeaderField("Content-Length"));
 } catch (MalformedURLException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 if (conn != null) {
 conn.disconnect();
 }
 }
 System.out.println("獲得文件大小 end......" + result);
 return result;
 }
 
 // 具體細節求出每個線程的開始位置和文件下載大小
 public int[][] getPosAndLength() {
 int[][] result = new int[threadNum][2];
 int fileLength = (int) getFileLength();
 int every = fileLength % threadNum == 0 ? fileLength / threadNum
 : fileLength / threadNum + 1;
 for (int i = 0; i < result.length; i++) {
 int length = 0;
 if (i != result.length - 1) {
 length = every;
 } else {
 length = fileLength - i * every;
 }
 result[i][0] = i * every;
 result[i][1] = length;
 }
 return result;
 }
 
 // 合并文件
 public void mergeFiles() {
 System.out.println("合并文件 start......");
 OutputStream out = null;
 try {
 out = new FileOutputStream(savePath);
 for (int i = 1; i <= threadNum; i++) {
 InputStream in = new FileInputStream(savePath + i);
 byte[] bytes = new byte[2048];
 int read = 0;
 while ((read = in.read(bytes)) != -1) {
 out.write(bytes, 0, read);
 out.flush();
 }
 if (in != null) {
 in.close();
 new File(savePath + i).delete();
 }
 }
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 if (out != null) {
 try {
 out.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 System.out.println("合并文件 end......");
 }
 
 public String getSavePath() {
 return savePath;
 }
 
 public void setSavePath(String savePath) {
 this.savePath = savePath;
 }
 
 public int getThreadNum() {
 return threadNum;
 }
 
 public void setThreadNum(int threadNum) {
 this.threadNum = threadNum;
 }
 
 public String getUrlFile() {
 return urlFile;
 }
 
 public void setUrlFile(String urlFile) {
 this.urlFile = urlFile;
 }
 
 public boolean isStarted() {
 return isStarted;
 }
 
 public void setStarted(boolean isStarted) {
 this.isStarted = isStarted;
 }
 
 public List<DownloadThread> getDownloadList() {
 return downloadList;
 }
 
 public void setDownloadList(List<DownloadThread> downloadList) {
 this.downloadList = downloadList;
 }
}

 2、DownloadThread類

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
 
public class DownloadThread implements Runnable {
 // 當前第幾個線程 , 用于給下載文件起名 file1 file2 file3 ...
 private int whichThread;
 // 監聽單一線程下載是否完成
 private boolean isFinish;
 // 本線程要下載的文件字節數
 private int length;
 // 本線程向服務器發送請求時輸入流的首位置
 private int startPosition;
 // 保存的路徑
 private String savePath;
 // 要下載的文件 , 用于創建連接
 private String url;
 
 public void run() {
 HttpURLConnection conn = null;
 InputStream in = null;
 OutputStream out = null;
 try {
 System.out.println("正在執行的線程:" + whichThread);
 URL fileUrl = new URL(url);
 // 與服務器創建連接
 conn = (HttpURLConnection) fileUrl.openConnection();
 // 下載使用get請求
 conn.setRequestMethod("GET");
 // 告訴服務器 , 我是火狐 , 不要不讓我下載。
 conn.setRequestProperty(
 "User-Agent",
 "Firefox Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3");
 // 這里是設置文件輸入流的首位置
 conn.setRequestProperty("Range", "bytes=" + startPosition + "-");
 // 與服務器創建連接
 conn.connect();
 // 獲得輸入流
 in = conn.getInputStream();
 // 在硬盤上創建file1 , file2 , ...這樣的文件 , 準備往里面寫東西
 out = new FileOutputStream(savePath + whichThread);
 // 用于寫入的字節數組
 byte[] bytes = new byte[4096];
 // 一共下載了多少字節
 int count = 0;
 // 單次讀取的字節數
 int read = 0;
 while ((read = in.read(bytes)) != -1) {
 // 檢查一下是不是下載到了本線程需要的長度
 if (length - count < bytes.length) {
 // 比如說本線程還需要900字節,但是已經讀取1000
 // 字節,則用要本線程總下載長度減去
 // 已經下載的長度
 read = length - count;
 }
 // 將準確的字節寫入輸出流
 out.write(bytes, 0, read);
 // 已經下載的字節數加上本次循環字節數
 count = count + read;
 // 如果下載字節達到本線程所需要字節數,消除循環,
 // 停止下載
 if (count == length) {
 break;
 }
 }
 // 將監視變量設置為true
 isFinish = true;
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 // 最后進行輸入、輸出、連接的關閉
 if (in != null) {
 try {
 in.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 if (out != null) {
 try {
 out.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 if (conn != null) {
 conn.disconnect();
 }
 }
 }
 
 public int getStartPosition() {
 return startPosition;
 }
 
 public void setStartPosition(int startPosition) {
 this.startPosition = startPosition;
 }
 
 public String getUrl() {
 return url;
 }
 
 public void setUrl(String url) {
 this.url = url;
 }
 
 public int getWhichThread() {
 return whichThread;
 }
 
 public void setWhichThread(int whichThread) {
 this.whichThread = whichThread;
 }
 
 public int getLength() {
 return length;
 }
 
 public void setLength(int length) {
 this.length = length;
 }
 
 public String getSavePath() {
 return savePath;
 }
 
 public void setSavePath(String savePath) {
 this.savePath = savePath;
 }
 
 public DownloadThread(int whichThread, int length, int startPosition,
 String savePath, String url) {
 super();
 this.whichThread = whichThread;
 this.length = length;
 this.startPosition = startPosition;
 this.savePath = savePath;
 this.url = url;
 }
 
 public DownloadThread() {
 super();
 }
 
 public boolean isFinish() {
 return isFinish;
 }
 
 public void setFinish(boolean isFinish) {
 this.isFinish = isFinish;
 }
}

3、TestDownload測試類

public class TestDownload {
 
 public static void main(String[] args) {
 DownloadManager downloadManager = new DownloadManager("d:/upload/09018417.zip" , 5 , "http://10.1.2.65:8080/cetvossFront/09018417.zip");
 downloadManager.action();
 }
}

關于怎么在java中利用多線程實現文件下載問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女