一个网友正好需要这个东西,我就把几个技术整合到了一起。包括三个部分,实现时也是逐个做到的
多线程的文件下载,HTTP协议
把这个功能做成一个HTTP的服务,侦听在某个端口上,方便非Java的系统使用
把这个功能封装为一个Windows服务,在机器启动时可以自动启动
我们逐个看程序。
一、多线程下载
这个主要使用了HTTP协议里面的一个Range参数,他设置了你读取数据的其实位置和终止位置。 经常使用flashget的用户在查看连接的详细信息时,应该经常看到这个东西。比如
Range:bytes=100-2000
代表从100个字节的位置开始读取,到2000个字节的位置结束,应读取1900个字节。
程序首先拿到文件的长度,然后分配几个线程去分别读取各自的一段,使用了
RandomAccessFile
进行随机位置的读写。
下面是完整的下载的代码。
package net.java2000.tools;import java.io.BufferedInputStream;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;import java.net.URL;import java.net.URLConnection;/*** HTTP的多线程下载工具。** @*/public class HTTPDownloader extends Thread { // 要下载的页面 private String page; // 保存的路径 private String savePath; // 线程数 private int threadNumber = 2; // 来源地址 private String referer; // 最小的块尺寸。如果文件尺寸除以线程数小于这个,则会减少线程数。 private int MIN_BLOCK = 10 * 1024; public static void main(String[] args) throws Exception { HTTPDownloader d = new HTTPDownloader("http://www.xxxx.net/xxxx.rar", "d://xxxx.rar", 10); d.down(); } public void run() { try { down(); } catch (Exception e) { e.printStackTrace(); } } /** * 下载操作 * * @throws Exception */ public void down() throws Exception { URL url = new URL(page); // 创建URL URLConnection con = url.openConnection(); // 建立连接 int contentLen = con.getContentLength(); // 获得资源长度 if (contentLen / MIN_BLOCK + 1 10) { threadNumber = 10; } int begin = 0; int step = contentLen / threadNumber; int end = 0; for (int i = 0; i contentLen) { end = contentLen; } new HTTPDownloaderThread(this, i, begin, end).start(); begin = end; } } public HTTPDownloader() { } /** * 下载 * * @param page 被下载的页面 * @param savePath 保存的路径 */ public HTTPDownloader(String page, String savePath) { this(page, savePath, 10); } /** * 下载 * * @param page 被下载的页面 * @param savePath 保存的路径 * @param threadNumber 线程数 */ public HTTPDownloader(String page, String savePath, int threadNumber) { this(page, page, savePath, 10); } /** * 下载 * * @param page 被下载的页面 * @param savePath 保存的路径 * @param threadNumber 线程数 * @param referer 来源 */ public HTTPDownloader(String page, String referer, String savePath, int threadNumber) { this.page = page; this.savePath = savePath; this.threadNumber = threadNumber; this.referer = referer; } public String getPage() { return page; } public void setPage(String page) { this.page = page; } public String getSavePath() { return savePath; } public void setSavePath(String savePath) { this.savePath = savePath; } public int getThreadNumber() { return threadNumber; } public void setThreadNumber(int threadNumber) { this.threadNumber = threadNumber; } public String getReferer() { return referer; } public void setReferer(String referer) { this.referer = referer; }}/*** 下载线程*< 失败是成功的亲娘,没有失败哪来的成功呢?诺贝尔如果不经历千万次的失败,