程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> HTTP多線程斷點續傳下載的嘗試

HTTP多線程斷點續傳下載的嘗試

編輯:關於JAVA

直接看代碼吧,廢話一點不多說。

功能介紹:

1 多線程HTTP下載

2 支持斷點續傳

3 臨時文件下載,成功後改名

4 提供防盜鏈的破解

Java代碼

1.import java.io.BufferedInputStream;
2.import java.io.BufferedWriter;
3.import java.io.File;
4.import java.io.OutputStreamWriter;
5.import java.io.RandomAccessFile;
6.import java.net.Socket;
7.import java.net.URL;
8.import java.net.URLConnection;
9.import java.util.HashMap;
10.import java.util.Map;
11.
12./**
13. * HTTP的多線程下載工具。
14. *
15. * @author 趙學慶 www.java2000.net
16. */
17.public class HTTPDownloader extends Thread {
18.  // 要下載的頁面
19.  private String page;
20.
21.  // 保存的路徑
22.  private String savePath;
23.
24.  // 線程數
25.  private int threadNumber = 2;
26.
27.  // 來源地址
28.  private String referer;
29.
30.  private String cookie;
31.
32.  int threadPointer = 0;
33.
34.  private Map<Integer, HTTPDownloaderThread> threadPool = new HashMap<Integer, HTTPDownloaderThread>(); // 線程遲
35.
36.  // 最小的塊尺寸。如果文件尺寸除以線程數小於這個,則會減少線程數。 37.  private int MIN_BLOCK = 10 * 1024;
38.
39.  public static void main(String[] args) throws Exception {
40.    HTTPDownloader d = new HTTPDownloader("http://www.xxxxx.com/a.rar", null, "d://a.rar", 10, null);
41.    d.down();
42.  }
43.
44.  public void run() {
45.    try {
46.      down();
47.    } catch (Exception e) {
48.      e.printStackTrace();
49.    }
50.  }
51.
52.  /**
53.   * 下載操作
54.   *
55.   * @throws Exception
56.   */
57.  public void down() throws Exception {
58.    URL url = new URL(page); // 創建URL
59.    URLConnection con = url.openConnection(); // 建立連接
60.    con.setRequestProperty("Referer", referer == null ? page : referer);
61.    con.setRequestProperty("UserAgent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; flashget)");
62.    int contentLen = con.getContentLength(); // 獲得資源長度
63.    if ((contentLen / MIN_BLOCK + 1) < threadNumber) {
64.      threadNumber = contentLen / MIN_BLOCK + 1; // 調整下載線程數  65.    }
66.    if (threadNumber > 10) {
67.      threadNumber = 10;
68.    }
69.    int begin = 0;
70.    int step = contentLen / threadNumber + 1;
71.    int end = 0;
72.    HTTPDownloaderThread thread;
73.    for (threadPointer = 0; threadPointer < threadNumber; threadPointer++) {
74.      end += step;
75.      if (end > contentLen) {
76.        end = contentLen;
77.      }
78.      thread = new HTTPDownloaderThread(this, threadPointer, begin, end);
79.      threadPool.put(threadPointer, thread);
80.      thread.start();
81.      begin = end;
82.    }
83.  }
84.
85.  /**
86.   * 一個線程完活了。
87.   *
88.   * @param id 完活的線程id
89.   */
90.  public synchronized void finished(int id) {
91.    threadNumber--;
92.    threadPool.remove(id);
93.    if (threadNumber <= 0) {
94.      System.out.println("FINISHED:" + savePath);
95.      File f1 = new File(savePath + ".tmp");
96.      File f2 = new File(savePath);
97.      // 如果目標文件已經存在,則嘗試刪除它
98.      // 最多嘗試3次,間隔1秒鐘。
99.      int times = 3;
100.      while (f2.exists() && times > 0) {
101.        if (f2.delete()) {
102.          break;
103.        }
104.        try {
105.          Thread.sleep(1000);
106.        } catch (InterruptedException e) {
107.          e.printStackTrace();
108.        }
109.        times--;
110.      }
111.      if (!f2.exists()) {
112.        if (!f1.renameTo(f2)) {
113.          System.out.println("改名失敗!");
114.        }
115.      } else {
116.        System.out.println("目標文件存在,且無法刪除,無法改名");
117.      }
118.    } else {
119.      int size = 0;
120.      HTTPDownloaderThread o = null;
121.      // 嘗試查找一個可以分擔的線程
122.      for (HTTPDownloaderThread thread : threadPool.values()) {
123.        if (thread.endPos - thread.curPos > size) {
124.          size = thread.endPos - thread.curPos;
125.          o = thread;
126.        }
127.      }
128.      if (size > MIN_BLOCK * 2) {
129.        if (o.isAlive()) {
130.          int endPos = o.endPos;
131.          int beginPos = o.endPos - ((o.endPos - o.curPos) / 2);
132.          o.endPos = beginPos;
133.          threadNumber++;
134.          threadPointer++;
135.          HTTPDownloaderThread thread = new HTTPDownloaderThread(this, threadPointer, beginPos, endPos);
136.          threadPool.put(threadPointer, thread);
137.          System.out.println("A Help Thread for " + o.id + " is started with:" + threadPointer);
138.          thread.start();
139.        }
140.      }
141.    }
142.  }
143.
144.  public HTTPDownloader() {
145.  }
146.
147.  /**
148.   * 下載
149.   *
150.   * @param page 被下載的頁面
151.   * @param savePath 保存的路徑
152.   */
153.  public HTTPDownloader(String page, String savePath) {
154.    this(page, savePath, 10);
155.  }
156.
157.  /**
158.   * 下載
159.   *
160.   * @param page 被下載的頁面
161.   * @param savePath 保存的路徑
162.   * @param threadNumber 線程數
163.   */
164.  public HTTPDownloader(String page, String savePath, int threadNumber) {
165.    this(page, page, savePath, 10, null);
166.  }
167.
168.  /**
169.   * 下載
170.   *
171.   * @param page 被下載的頁面
172.   * @param savePath 保存的路徑
173.   * @param threadNumber 線程數
174.   * @param referer 來源
175.   */
176.  public HTTPDownloader(String page, String referer, String savePath, int threadNumber, String cookie) {
177.    this.page = page;
178.    this.savePath = savePath;
179.    this.threadNumber = threadNumber;
180.    this.referer = referer;
181.  }
182.
183.  public String getPage() {
184.    return page;
185.  }
186.
187.  public void setPage(String page) {
188.    this.page = page;
189.  }
190.
191.  public String getSavePath() {
192.    return savePath;
193.  }
194.
195.  public void setSavePath(String savePath) {
196.    this.savePath = savePath;
197.  }
198.
199.  public int getThreadNumber() {
200.    return threadNumber;
201.  }
202.
203.  public void setThreadNumber(int threadNumber) {
204.    this.threadNumber = threadNumber;
205.  }
206.
207.  public String getReferer() {
208.    return referer;
209.  }
210.
211.  public void setReferer(String referer) {
212.    this.referer = referer;
213.  }
214.
215.  public String getCookie() {
216.    return cookie;
217.  }
218.
219.  public void setCookie(String cookie) {
220.    this.cookie = cookie;
221.  }
222.}
223.
224./**
225. * 下載線程
226. *
227. * @author 趙學慶 www.java2000.net
228. */
229.class HTTPDownloaderThread extends Thread {
230.  HTTPDownloader manager;
231.
232.  int startPos;
233.
234.  int endPos;
235.
236.  int id;
237.
238.  int curPos;
239.
240.  int BUFFER_SIZE = 40960;
241.
242.  int readByte = 0;
243.
244.  HTTPDownloaderThread(HTTPDownloader manager, int id, int startPos, int endPos) {
245.    this.id = id;
246.    this.manager = manager;
247.    this.startPos = startPos;
248.    this.endPos = endPos;
249.  }
250.
251.  public void run() {
252.    System.out.println("線程" + id + "啟動," + startPos + "-" + endPos);
253.    // 創建一個buff
254.    BufferedInputStream bis = null;
255.    RandomAccessFile fos = null;
256.    // 緩沖區大小
257.    byte[] buf = new byte[BUFFER_SIZE];
258.    boolean timeout = false;
259.    Socket socket = null;
260.    try {
261.      curPos = startPos;
262.      File file = new File(manager.getSavePath() + ".tmp");
263.      // 創建RandomAccessFile
264.      fos = new RandomAccessFile(file, "rw");
265.      // 從startPos開始
266.      fos.seek(startPos);
267.      int index = manager.getPage().indexOf("/", 8);
268.      String host = manager.getPage().substring(7, index);
269.      // System.out.println(host);
270.      socket = new Socket(host, 80);
271.      socket.setSoTimeout(30000);
272.      // 寫入數據
273.      BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
274.      StringBuilder b = new StringBuilder();
275.      b.append("GET " + manager.getPage().substring(index) + " HTTP/1.1\r\n");
276.      b.append("Host: " + host + "\r\n");
277.      b.append("Referer: " + (manager.getReferer() == null ? manager.getPage() : manager.getReferer()) + "\r\n");
278.      b.append("UserAgent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; flashget; \r\n");
279.      b.append("Range: bytes=" + startPos + "-" + endPos + "\r\n");
280.      b.append("\r\n");
281.      // System.out.println(b.toString());
282.      wr.write(b.toString());
283.      wr.flush();
284.      // 下面一段向根據文件寫入數據,curPos為當前寫入的未知,這裡會判斷是否小於endPos,
285.      // 如果超過endPos就代表該線程已經執行完畢
286.      bis = new BufferedInputStream(socket.getInputStream());
287.      // 讀取直到換行
288.      int ch;
289.      boolean foundBR = false;
290.      while (true) {
291.        ch = bis.read();
292.        if (ch == 0xD) {
293.          ch = bis.read();
294.          if (ch == 0xA) {
295.            if (foundBR) {
296.              break;
297.            }
298.            foundBR = true;
299.          } else {
300.            foundBR = false;
301.          }
302.        } else {
303.          foundBR = false;
304.        }
305.      }
306.      int len = -1;
307.      while (curPos < endPos) {
308.        // System.out.println(id + "=" + (endPos - curPos));
309.        len = bis.read(buf, 0, BUFFER_SIZE);
310.        if (len == -1) {
311.          break;
312.        }
313.        fos.write(buf, 0, len);
314.        // System.out.println(id + "=Write OK!");
315.        curPos = curPos + len;
316.        if (curPos > endPos) {
317.          // 獲取正確讀取的字節數
318.          readByte += len - (curPos - endPos) + 1;
319.        } else {
320.          readByte += len;
321.        }
322.      }
323.      System.out.println("線程" + id + "已經下載完畢:" + readByte);
324.    } catch (Exception ex) {
325.      timeout = true;
326.    } finally {
327.      if (bis != null) {
328.        try {
329.          bis.close();
330.        } catch (Exception e) {
331.          System.out.println("關閉文件失敗(1)!");
332.        }
333.      }
334.      if (fos != null) {
335.        try {
336.          fos.close();
337.        } catch (Exception e) {
338.          System.out.println("關閉文件失敗(2)!");
339.        }
340.      }
341.      if (socket != null) {
342.        try {
343.          socket.close();
344.        } catch (Exception e) {
345.          System.out.println("關閉鏈接失敗!");
346.        }
347.      }
348.    }
349. if (timeout) {
350.          System.out.println(id + " timeout, restart...");
351.          new HTTPDownloaderThread(manager, id, curPos, endPos).start();
352.        } else {
353.          manager.finished(id);
354.        }
355.      }
356.    }
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved