Java多线程下载

package org.yang.utils;

/**
 * @author 杨志永
 * email [email protected]
 * QQ 929168233
 * Date 2012-9-10
 */

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

public class MultiDownload implements Runnable {
	/** threadId 表示当前线程的Id .只能外界只能获取不能设置 */
	private int threadId;

	/** threadNumbers 表示用多少条线程来下载. 外界可以设置下载的线程数,默认为5条线程。可以get和set */
	private int threadNumbers = 5;

	/** 每条线程要下载的块大小,单位为byte。只能外界只能获取不能设置 */
	private int blockSize;

	/** url 表示网络文件的URL地址的字符串表示形式 . 只能从外界设置(set),设置完后可以get */
	private String url;

	/** savePathDir 表示要保存的本地路径目录 ,必须要设置。注意是目录 */
	private String savePathDir;

	/** saveFile 表示要保存的本地文件 */
	private File saveFile;

	/** fileName 表示文件名 */
	private String fileName;

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public int getThreadId() {
		return threadId;
	}

	public int getThreadNumbers() {
		return threadNumbers;
	}

	public void setThreadNumbers(int threadNumbers) {
		this.threadNumbers = threadNumbers;
	}

	public int getBlockSize() {
		return blockSize;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getSavePathDir() {
		return savePathDir;
	}

	public void setSavePathDir(String savePathDir) {
		this.savePathDir = savePathDir;
	}

	public File getSaveFile() {
		return saveFile;
	}

	public void setSaveFile(File saveFile) {
		this.saveFile = saveFile;
	}

	public MultiDownload() {
	}

	/**
	 * 
	 * @param threadId
	 *            当前线程的Id
	 * @param blockSize
	 *            每条线程要下载的大小,单位为byte
	 * @param url
	 *            网络资源的url字符串
	 * @param saveFile
	 *            要保存的路径
	 */
	public MultiDownload(int threadId, int blockSize, String url, File saveFile) {
		super();
		this.blockSize = blockSize;
		this.threadId = threadId;
		this.url = url;
		this.saveFile = saveFile;
	}

	public void startDownloadFile() throws IOException {
		/** 创建一个URL对象,参数为网络资源的字符串,用来与网络资源文件建立连接 */
		URL url = new URL(this.url);

		/** 创建一个网络连接对象,并打开该连接 */
		HttpURLConnection httpURLConnection = (HttpURLConnection) url
				.openConnection();

		/** 设置超时 */
		httpURLConnection.setConnectTimeout(5000);

		/** 设置请求方式,这里设置为GET */
		httpURLConnection.setRequestMethod("GET");

		try {

			/** 判断连接的返回状态码,200表示为正常状态 */
			if (httpURLConnection.getResponseCode() == 200) {
				/** 获取网络文件的总大小,单位为byte */
				int fileLength = httpURLConnection.getContentLength();

				System.out.println("要下载的文件总大小为: " + fileLength + " bytes");
				System.out.println("要下载的文件名为: " + this.getFileName());

				/** 要保存为本地的路径表示的文件对象,为 保存的目录 + 网络文件的文件名 */
				File saveFiles = new File(savePathDir + File.separator
						+ this.getFileName());

				/** 建立一个随机访问的文件对象,并设置它的大小为网络文件资源的文件总大小,即 fileLength */
				RandomAccessFile randomAccessFile = new RandomAccessFile(
						saveFiles, "rwd");
				randomAccessFile.setLength(fileLength);
				randomAccessFile.close();

				/** 计算每条线程要下载的块大小blockSize,单位为byte */
				int blockSize = fileLength % this.threadNumbers == 0 ? fileLength
						/ this.threadNumbers
						: fileLength / this.threadNumbers + 1;
				System.out.println("每条线程要下载的文件大小为: " + blockSize + " bytes");

				/** 启动所有线程来进行下载 */
				for (int threadId = 0; threadId < this.threadNumbers; threadId++) {

					new Thread(new MultiDownload(threadId, blockSize, this.url,
							saveFiles)).start();
				}

			}
		} catch (Exception e) {
			System.out.println("连接出错啦:第[" + this.threadId + "]条线程:");
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		System.out.println("第" + this.threadId + "条线程启动!");
		/** start为每条线程从该位置开始下载 ,公式为 【开始位置=线程的ID*每条线程要下载的块大小】 */
		int start = this.threadId * this.blockSize;

		/**
		 * end 为每条线程从该位置结束下载 ,公式为 【结束位置=(线程的ID+1)*每条线程要下载的块大小 -1
		 * ,减1是因为文件的长度表示范围为:0~fileLength】
		 */
		int end = (this.threadId + 1) * this.blockSize - 1;

		try {
			/** 打开要保存的本地文件的随机访问文件对象 */
			RandomAccessFile randomAccessFile = new RandomAccessFile(
					this.saveFile, "rwd");
			/** 将文件指针定位到每条线程的 start (即从start位置开始下载)的位置 */
			randomAccessFile.seek(start);

			/** 打开连接 */
			HttpURLConnection httpURLConnection = (HttpURLConnection) (new URL(
					this.url)).openConnection();
			/** 设置超时 */
			httpURLConnection.setConnectTimeout(5000);
			/** 设置请求方式 */
			httpURLConnection.setRequestMethod("GET");

			/** 设置从网络资源文件数据位置从start开始处,到end结束位置的文件数据 */
			httpURLConnection.setRequestProperty("Range", "bytes=" + start
					+ "-" + end);

			/** 如果请求成功,(成功的状态码为206) 则写入本地文件中 */

			if (httpURLConnection.getResponseCode() == 206) {
				InputStream inputStream = httpURLConnection.getInputStream();
				byte[] buffer = new byte[1024];
				int length = 0;
				while ((length = inputStream.read(buffer)) != -1) {
					randomAccessFile.write(buffer, 0, length);
				}
				System.out.println("第" + this.threadId + "线程下载完毕");

			}
		} catch (Exception e) {
			System.out.println("第" + this.threadId + "线程出错!");
			e.printStackTrace();
		}

	}

	/** 获取网络文件资源的文件名 */
	public String getFileName() {
		
		/**  如果没有显式设置文件名,则从网络文件资源中设置 */
		
		if ( fileName == null )
		{
			 return url.substring(url.lastIndexOf("/") + 1);   
		}
		return fileName;
	}

}

 

你可能感兴趣的:(java,多线程,exception,String,网络,url)