多线程分段下载文件
原理
先獲取文件大小,然后分段分配任務(wù)給線程下載
在開(kāi)始多線程下載前得先得知下載文件的大小,如果在之前的流程中并沒(méi)有告知文件大小則可以使用HTTP請(qǐng)求方法 HEAD,這個(gè)請(qǐng)求方法類(lèi)似于 GET 請(qǐng)求,只不過(guò)返回的響應(yīng)中沒(méi)有具體的內(nèi)容,用于獲取報(bào)頭,在頭部中可以找到字段content-length就是文件大小了。
得知文件長(zhǎng)度后應(yīng)分割需要下載的起止位置以便之后使用。
有具體位置后就可以啟動(dòng)多線程發(fā)送網(wǎng)絡(luò)請(qǐng)求,在網(wǎng)絡(luò)請(qǐng)求中使用HTTP協(xié)議的頭部標(biāo)志Range,這個(gè)標(biāo)志的使用方法是Range:bytes=start-end。
實(shí)現(xiàn)
import java.io.*; import java.net.HttpURLConnection; import java.net.URL;/*** Created with IntelliJ IDEA.** @Auther: zlf* @Date: 2021/09/14/1:01* @Description:*/ public class MutiThreadDownload {private int threadCount = 5; // 下載線程數(shù)private long blocksize; // 每線程下載區(qū)塊大小private int runningThreadCount; // 正運(yùn)行線程數(shù)public int getThreadCount() {return threadCount;}public void setThreadCount(int threadCount) {this.threadCount = threadCount;}public long getBlocksize() {return blocksize;}public void setBlocksize(long blocksize) {this.blocksize = blocksize;}public int getRunningThreadCount() {return runningThreadCount;}public void setRunningThreadCount(int runningThreadCount) {this.runningThreadCount = runningThreadCount;}/*** @Description: 多線程分段下載* @Param: [url, filePath]* @return: void* @Author: zlf* @Date: 2021/9/14*/public void download(String url, String filePath) throws IOException {HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();int code = conn.getResponseCode();if (code == 200) {long size = conn.getContentLength();// 文件大小blocksize = size / threadCount;// 1.創(chuàng)建RandomAccessFile文件(可以隨機(jī)訪問(wèn))RandomAccessFile raf = new RandomAccessFile(new File(filePath), "rw");raf.setLength(size);// 2.多線程下載對(duì)應(yīng)區(qū)塊runningThreadCount = threadCount;for (int i = 1; i <= threadCount; i++) {long startIndex = (i - 1) * blocksize;long endIndex = i * blocksize - 1;if (i == threadCount) {endIndex = size - 1;}new DownloadThread(i, url, filePath,startIndex, endIndex).start();}}conn.disconnect();}/**** @Description: 分段下載的線程* @Param: * @return: * @Author: zlf* @Date: 2021/9/14*/private class DownloadThread extends Thread {private int id;private String url;private long startIndex;private long endIndex;private String filePath;public DownloadThread(int id, String url, String filePath, long startIndex, long endIndex) {this.id = id;this.url = url;this.startIndex = startIndex;this.filePath = filePath;this.endIndex = endIndex;}@Overridepublic void run() {try {HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();conn.setRequestMethod("GET");// 1.讀取文件斷點(diǎn)位置curIndexint curIndex = 0;File indexFile = new File("indexFile_"+id);if (indexFile.exists() && indexFile.length() > 0) {FileInputStream fis = new FileInputStream(indexFile);BufferedReader br = new BufferedReader(new InputStreamReader(fis));curIndex = Integer.valueOf(br.readLine());startIndex += curIndex;fis.close();}// 2.從startIndex位置下載文件, 并從startIndex位置寫(xiě)入raf文件conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);InputStream is = conn.getInputStream();RandomAccessFile raf = new RandomAccessFile(new File(filePath), "rw");raf.seek(startIndex);int len = 0;byte[] buffer = new byte[1024*1024];while ((len = is.read(buffer)) != -1) {raf.write(buffer, 0, len);// 更新斷點(diǎn)位置RandomAccessFile indexRaf = new RandomAccessFile(indexFile, "rwd");curIndex += len;indexRaf.write(String.valueOf(curIndex).getBytes());indexRaf.close();}is.close();raf.close();} catch (Exception e) {e.printStackTrace();} finally {// 3.所有線程下載完,刪除斷點(diǎn)位置文件indexFilesynchronized (MutiThreadDownload.class){if (--runningThreadCount == 0) {for (int i = 1; i <= threadCount; i++) new File("indexFile_"+i).delete();}}}}}public static void main(String[] args) throws IOException {MutiThreadDownload mutiThreadDownload = new MutiThreadDownload();mutiThreadDownload.setRunningThreadCount(5);mutiThreadDownload.download("http://img.netbian.com/file/2020/0904/de2f77ed1090735b441ba5e4c2b460ca.jpg","D:/a.jpg");}}總結(jié)
- 上一篇: 单片机四位数加减计算机程序,51单片机简
- 下一篇: Vue组件基础