您好,登錄后才能下訂單哦!
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中怎么利用多線程實現文件下載功能的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。