Java 多线程下载

/**
 * 多线程下载工具类:
 * 		如果要实现断点下载,要额外增加一个配置文件
 * 		所有的断点下载工具都会在下载开始时生成两个文件:一个是与网络资源具有相同大小的空文件,一个是配置文件
 * 		该配置文件分别记录每个线程已经下载到哪个字节,当网络断开再次开始下载时,每个线程根据配置文件里记录的位置向后下载即可
 * 
 * 程序中DownUtils类中的download()方法负责按如下步骤来实现多线程下载
 * 1.创建URL对象
 * 2.获取指定URL对象所指向的资源大小,通过URLConnection类中getConnectLength()方法获得
 * 3.在本地磁盘上创建一个与网络资源具有相同大小的空文件
 * 4.计算每个线程应该下载网络资源的哪个部分(从哪个字节开始,到哪个字节结束)
 * 5.依次创建、启动多个线程来下载网络资源的指定部分
 */
package codes17;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class DownUtil {
	private String path; // 定义下载资源的路径
	private String targetFile; // 指定所下载的文件的保存位置
	private int threadNum; // 定义需要使用多少个线程下载资源
	private DownThread[] threads; // 定义下载的线程对象
	private int fileSize; // 定义下载的文件的总大小

	public DownUtil(String path, String targetFile, int threadNum) {
		super();
		this.path = path;
		this.targetFile = targetFile;
		this.threadNum = threadNum;
		threads = new DownThread[threadNum];
	}

	public void download() {
		URL url;
		HttpURLConnection conn = null;
		RandomAccessFile file = null;
		try {
			url = new URL(path);
			conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5 * 1000);
			conn.setRequestMethod("GET");
			conn.setRequestProperty(
					"Accept",
					"image/gif,image/jpeg,image/pjpeg,"
							+ "application/x-shockwave-flash,application/xaml+xml,"
							+ "application/vnd.ms-xpsdocument,application/x-ms-xbap,"
							+ "application/x-ms-application, application/vnd.ms-excel,"
							+ "application/vnd.ms-powerpoint,application/msword, */*");
			conn.setRequestProperty("Accept-Language", "zh-CH");
			conn.setRequestProperty("Charset", "UTF-8");
			conn.setRequestProperty("Connection", "Keep-Alive");

			fileSize = conn.getContentLength(); // 得到文件大小
			conn.disconnect();
			int currentPartSize = fileSize / threadNum + 1;
			file = new RandomAccessFile(targetFile, "rw");
			file.setLength(fileSize); // 设置本地文件大小

			for (int i = 0; i < threadNum; i++) {
				int startPos = i * currentPartSize; // 计算每个线程下载的开始位置
				RandomAccessFile currentPart = new RandomAccessFile(targetFile,
						"rw"); // 每个线程使用一个RandAccessFile进行下载
				currentPart.seek(startPos); // 定位该线程的下载位置
				threads[i] = new DownThread(startPos, currentPartSize,
						currentPart); // 创建下载线程
				threads[i].start();
			}

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (file != null) {
				try {
					file.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 获取下载的完成百分比
	 * 
	 * @return 返回已经完成的百分比
	 */
	public double getCompleteRate() {
		// 统计多个线程已经下载的总大小
		int sumSize = 0;
		for (int i = 0; i < threadNum; i++) {
			sumSize += threads[i].length;
		}
		return sumSize * 1.0 / fileSize;
	}

	private class DownThread extends Thread {
		private int startPos; // 当前线程的下载位置
		private int currentPartSize; // 定义当前线程负责下载的文件大小
		private RandomAccessFile currentPart; // 当前线程需要下载的文件块
		public int length; // 定义该线程已下载的字数

		public DownThread(int startPos, int currentPartSize,
				RandomAccessFile currentPart) {
			this.startPos = startPos;
			this.currentPartSize = currentPartSize;
			this.currentPart = currentPart;
		}

		public void run() {
			HttpURLConnection conn = null;
			InputStream inStream = null;
			try {
				URL url = new URL(path);
				conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5 * 1000);
				conn.setRequestMethod("GET");
				conn.setRequestProperty(
						"Accept",
						"image/gif,image/jpeg,image/pjpeg,"
								+ "application/x-shockwave-flash,application/xaml+xml,"
								+ "application/vnd.ms-xpsdocument,application/x-ms-xbap,"
								+ "application/x-ms-application, application/vnd.ms-excel,"
								+ "application/vnd.ms-powerpoint,application/msword, */*");
				conn.setRequestProperty("Accept-Language", "zh-CH");
				conn.setRequestProperty("Charset", "UTF-8");

				inStream = conn.getInputStream();
				inStream.skip(startPos); // 跳过startPos个字节,表明该线程只下载自己负责的那部分文件
				byte[] buffer = new byte[1024];
				int hasRead = 0;
				// 读取网络数据,并写入本地文件
				while (length < currentPartSize
						&& (hasRead = inStream.read(buffer)) != -1) {
					currentPart.write(buffer, 0, hasRead);
					length += hasRead; // 累计该线程下载的总大小
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (currentPart != null)
						currentPart.close();
					if (inStream != null)
						inStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}
	}

}

主程序

package codes17;

public class MultiThreadDown {

	public static void main(String[] args) {
		// 初始化DownUtil 对象
		final DownUtil downUtil = new DownUtil(
				"http://softdownload.hao123.com/hao123-soft-online-bcs/soft/Y/2013-07-18_YoudaoDict_baidu.alading.exe",
				"YoudaoDict_baidu.alading.exe", 10);
		downUtil.download(); // 开始下载
		new Thread() {
			public void run() {
				while (downUtil.getCompleteRate() < 1) {
					// 每个0.1秒查询一次任务的完成进度,GUI程序中可根据该进度来绘制进度条
					System.out.println("已下载:" + downUtil.getCompleteRate()
							* 100 + "%");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} while (downUtil.getCompleteRate() >= 1) {
					System.out.println("下载完成");
					break;
				}
			}
		}.start();
	}

}

输出结果:

已下载:0.0%
已下载:19.772402605784702%
已下载:30.009086110800354%
已下载:37.48737840962224%
已下载:40.051425809431194%
已下载:44.387157244936304%
已下载:53.9980501077138%
已下载:80.66207412889513%
下载完成


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值