首页 > 代码库 > Java 多线程下载示例

Java 多线程下载示例


项目结构:


技术分享













FileDownload.java:

package com.wl.download;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.DecimalFormat;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;

import com.wl.util.DownLoadThread;
import com.wl.util.HttpClientFactory;

public class FileDownload {
	
	public static void main(String[] args) {
		long startTime = System.currentTimeMillis();
		System.out.println(startTime);
		
		String srcFileUrl = "http://172.16.2.40:80/2014/12/gpfqpfvlwsvka2mj39pn.mprx";
		String destFilePath = "G:/download/destfile.mprx";
		//获取文件的大小
		long fileSize = getRemoteFileSize(srcFileUrl);
		
		/**
		 * 每个线程需要下载的文件大小   (自行调整)
		 */
		//long unitSize = 1024 ; //多线程太多 卡死你电脑没问题 
		
		long unitSize = 1024 * 1024 * 2;  //下载文件大小为  = 535.66M; 23559 millisecond
		
		//long unitSize = 1024 * 1024 * 50;  //下载文件大小为  = 535.66M; 35726 millisecond
		
		//long unitSize = fileSize;  //下载文件大小为  = 535.66M;  所使用时间  = 52865 millisecond
		
		//创建目的文件,并指定大小
		createFile(destFilePath, fileSize);
		//开几个线程去下载
		long threadCount = fileSize / unitSize;
		//写入文件的位置
		long offset = 0;
		
		if (fileSize <= unitSize) {
			// 如果远程文件尺寸小于等于unitSize
			DownLoadThread downloadThread = new DownLoadThread(srcFileUrl, destFilePath, offset, fileSize);
			Thread t = new Thread(downloadThread);
			t.setPriority(10);
			t.start();
			try {
				t.join();  //该方法作用:主线程(此处是 main函数执行的线程) 等待该下载线程结束
			} catch (InterruptedException e) {
			}
		}else{
			for (int i = 1; i <= threadCount; i++) {

				DownLoadThread downloadThread = new DownLoadThread(
						srcFileUrl, destFilePath, offset, unitSize);
				Thread t = new Thread(downloadThread);
				t.setPriority(10);
				t.start();
				offset = offset + unitSize;
			}
			if (fileSize % unitSize != 0) {
				// 如果不能整除,则需要再创建一个线程下载剩余字节
				DownLoadThread downloadThread = new DownLoadThread(srcFileUrl, destFilePath, offset, fileSize - unitSize * threadCount);
				Thread t = new Thread(downloadThread);
				t.setPriority(10);
				t.start();
				try {
					t.join(); //该方法作用:主线程(此处是 main函数执行的线程) 等待所有由  主线程产生的下载线程  结束
				} catch (InterruptedException e) {
				}
			}
		}
		
		long endTime = System.currentTimeMillis();
		System.out.println(endTime);
		System.out.println("下载文件大小为  = " + fileSize2String(fileSize)+ ";  所使用时间  = "+ (endTime - startTime) + " millisecond");
	}
	
	
	/**
	 * 获取文件大小
	 */
	
	private static long getRemoteFileSize(String srcFileUrl) {
		HttpClient httpClient = HttpClientFactory.getInstance().getHttpClient();
		HttpGet httpGet = new HttpGet(srcFileUrl);
		// 发送请求,返回响应
		HttpResponse response = null;
		
		try {
			response = httpClient.execute(httpGet);
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		}
		long result = response.getEntity().getContentLength();
		return result;
	}
	
	
	/**
	 * 创建指定大小的文件
	 * @param fileName
	 * @param fileSize
	 */
	private static void createFile(String fileName, long fileSize) {
		File newFile = new File(fileName);
		if(newFile.exists())newFile.delete();
		RandomAccessFile raf = null;
		try {
			raf = new RandomAccessFile(newFile, "rw");
			raf.setLength(fileSize);
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		} finally {
			try {
				if (raf != null) {
					raf.close();
				}
			} catch (IOException e) {
			}
		}

	}
	
	/**
	 * 获取大小字符串
	 * @param totalSize
	 * @return
	 */
	private static String fileSize2String(long totalSize){
		  String fileTotalSize="";
        DecimalFormat df = new DecimalFormat("0.00");
    	if(totalSize <1024){
    		fileTotalSize=totalSize+"B";
    	}else if(totalSize <1048576){
    		fileTotalSize=df.format((float)totalSize/1024)+"K";
    	}else if(totalSize <1073741824){
    		fileTotalSize=df.format((float)totalSize/1048576)+"M";
    	}else{
    		fileTotalSize=df.format((float)totalSize/1073741824)+"G";
    	}
    	return fileTotalSize;
	}
}

DownLoadThread.java 

package com.wl.util;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class DownLoadThread implements Runnable {
	
	private String url = null;// 待下载的文件
	private String file = null;// 本地存储路径
	private long offset = 0;// 偏移量
	private long length = 0;// 分配给本线程的下载字节数

	public DownLoadThread(String url, String file, long offset, long length) {
		this.url = url;
		this.file = file;
		this.offset = offset;
		this.length = length;
	}

	public void run() {
		BufferedInputStream bis = null;
		SaveItemFile saveItemFile = null;
		try {
			HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(
					this.url.replace(" ", "%20")).openConnection();
			httpURLConnection.setRequestMethod("GET");
			httpURLConnection.setRequestProperty("RANGE", "bytes="
					+ this.offset + "-" + (this.offset + this.length - 1));
			bis = new BufferedInputStream(httpURLConnection.getInputStream());
			
			saveItemFile = new SaveItemFile(file,offset);
			
			byte[] buff = new byte[1024*8];
			while ((length = bis.read(buff)) > 0 && offset < offset+length ) {
                //写入文件内容,返回最后写入的长度
				offset += saveItemFile.write(buff, 0, (int)length);
            }
		} catch (IOException e) {
		} finally {
			try {
				if (bis != null) {
					bis.close();
				}
				if(saveItemFile!=null){
					saveItemFile.close();
				}
			} catch (IOException e) {
			}

		}

	}
}

HttpClientFactory.java:

package com.wl.util;

import java.util.concurrent.TimeUnit;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

public class HttpClientFactory {

	private HttpClient httpClient = null;

	/**
	 * 本类可能存在的惟一的一个实例
	 */
	private static HttpClientFactory m_instance;

	/**
	 * 静态工厂方法
	 * 
	 * @return 返还ReadConfigation 类的单一实例
	 */
	public static HttpClientFactory getInstance() {
		if (null == m_instance) {
			m_instance = new HttpClientFactory();
		}
		return m_instance;
	}

	private HttpClientFactory() {

		// 设置组件参数, HTTP协议的版本,1.1/1.0/0.9
		HttpParams params = new BasicHttpParams();
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setUserAgent(params, "HttpComponents/1.1");
		HttpProtocolParams.setUseExpectContinue(params, true);

		// 设置连接超时时间
		int REQUEST_TIMEOUT = 30 * 1000; // 设置请求超时10秒钟
		int SO_TIMEOUT = 10 * 1000; // 设置等待数据超时时间10秒钟
		// HttpConnectionParams.setConnectionTimeout(params, REQUEST_TIMEOUT);
		// HttpConnectionParams.setSoTimeout(params, SO_TIMEOUT);
		params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
				REQUEST_TIMEOUT);
		params.setParameter(CoreConnectionPNames.SO_TIMEOUT, SO_TIMEOUT);

		// 设置访问协议
		SchemeRegistry schreg = new SchemeRegistry();
		schreg.register(new Scheme("http", 80, PlainSocketFactory
				.getSocketFactory()));
		schreg.register(new Scheme("https", 443, SSLSocketFactory
				.getSocketFactory()));

		// 多连接的线程安全的管理器
		PoolingClientConnectionManager pccm = new PoolingClientConnectionManager(
				schreg);
		pccm.setDefaultMaxPerRoute(50); // 每个主机的最大并行链接数
		pccm.setMaxTotal(100); // 客户端总并行链接最大数

		httpClient = new DefaultHttpClient(pccm, params);
		httpClient.getConnectionManager().closeIdleConnections(10,
				TimeUnit.SECONDS);

	}

	public DefaultHttpClient getHttpClient() {
		return (DefaultHttpClient) httpClient;
	}

}

SaveItemFile.java:

package com.wl.util;

import java.io.IOException;
import java.io.RandomAccessFile;

public class SaveItemFile {
    //存储文件
    private RandomAccessFile itemFile;
    
    public SaveItemFile() throws IOException {
        this("", 0);
    }
    
    /**
     * @param name 文件路径、名称
     * @param pos 写入点位置 position
     * @throws IOException
     */
    public SaveItemFile(String name, long pos) throws IOException {
        itemFile = new RandomAccessFile(name, "rw");//可读可写
        //在指定的pos位置开始写入数据
        itemFile.seek(pos);
    }
    
    /**
     * <b>function:</b> 同步方法写入文件
     * @author hoojo
     * @createDate 2011-9-26 下午12:21:22
     * @param buff 缓冲数组
     * @param start 起始位置
     * @param length 长度
     * @return
     */
    public int write(byte[] buff, int start, int length) {
        int i = -1;
        try {
            itemFile.write(buff, start, length);
            i = length;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return i;
    }
    
    public void close() throws IOException {
        if (itemFile != null) {
            itemFile.close();
        }
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.filedownload</groupId>
  <artifactId>filedownload</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
  
  	<dependency>
         <groupId>org.apache.httpcomponents</groupId>
         <artifactId>com.springsource.org.apache.httpcomponents.httpclient</artifactId>
         <version>4.2.1</version>
     </dependency>
  	
	
  </dependencies>
</project>

over  

多线程上传  未完待续........

Java 多线程下载示例