Java 使用多线程从网络下载文件

package com.sphere.multithread;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class MultiThreadDownload {

	// 线程池默认线程数量
	private static final int DEFAULT_THREAD_COUNTS = 3;
	
	// 创建线程池对象
	private Executor threadPool = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNTS);
	
	// 文件总长度
	private int fileTotalLength = 0;
	// 当前已下载的文件长度
	private int currentFileDownloadLength = 0;
	
	
	private class DownloadRunnable implements Runnable{

		private int threadId;	// 标识线程号
		private String url;
		private String fileName;
		
		private long startIndex;
		private long endIndex;
		
		public DownloadRunnable(int threadId, String url, String fileName, long start, long end){
			this.threadId = threadId;
			this.url = url;
			this.fileName = fileName;
			this.startIndex = start;
			this.endIndex = end;
		}
		
		
		@Override
		public void run() {
			System.out.println("线程"+threadId +"开始执行...");
			RandomAccessFile accessFile = null;
			InputStream inputStream = null;
			try {
				URL httpUrl = new URL(url);
				HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
				conn.setReadTimeout(5000);
				conn.setRequestMethod("GET");
				// 指定读取的开始和结束的位置
				conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
				accessFile = new RandomAccessFile(new File(fileName), "rwd");
				accessFile.seek(startIndex);
				inputStream = conn.getInputStream();
				byte[] buffer = new byte[8*1024];
				int len = 0;
				long currentIndex = startIndex;
				while((len = inputStream.read(buffer)) != -1){
					accessFile.write(buffer, 0, len);
					System.out.println("线程"+threadId +"正在读取"+currentIndex+"到"+(currentIndex+len) +"之间的字节.");
					currentIndex = currentIndex+len;
					synchronized(this){
						currentFileDownloadLength += len;
						if(currentFileDownloadLength == fileTotalLength){
							System.out.println("-------------------------------");
							System.out.println("文件读写完毕。 总长度为"+fileTotalLength + "个字节。 ");
						}
						
					}
				}
				
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				if (accessFile != null){
					try {
						accessFile.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if (inputStream != null){
					try {
						inputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	
	protected void downFileByMultiThread(String url){
		
		try{
			URL httpUrl = new URL(url);
			HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
			conn.setReadTimeout(5000);
			conn.setRequestMethod("GET");
			// 此连接的 URL 引用的资源的内容长度,或者如果内容长度未知,则返回 -1
			int countLength = conn.getContentLength();
			int block = countLength / DEFAULT_THREAD_COUNTS;
			fileTotalLength = countLength;
			
			String fileName = getFileName(url);
			File file = new File("C:\\"+fileName);
			
			for (int i = 0; i < DEFAULT_THREAD_COUNTS ; i++){
				long start = i * block;
				long end  = (i + 1) * block -1;
				if (i == DEFAULT_THREAD_COUNTS - 1){
					end = countLength;
				}
				DownloadRunnable runnable = new DownloadRunnable((i+1), url, file.getAbsolutePath(), start, end);
				threadPool.execute(runnable);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 得到图片的文件名
	 */
	public static String getFileName(String str){
		String fileName = str.substring(str.lastIndexOf("/") + 1);
		return fileName;
	}
}


测试类:

package com.sphere.multithread;

public class Test {
	
	public static void main(String[] args) {
		String url = "http://b.zol-img.com.cn/desk/bizhi/image/1/1920x1080/1348626500448.jpg";
		
		new MultiThreadDownload().downFileByMultiThread(url);
	}
	

}


打印的log信息如下:

    

线程1开始执行...

线程2开始执行...

线程3开始执行...

线程2正在读取100695到108887之间的字节.

线程2正在读取108887到117079之间的字节.

线程2正在读取117079到125271之间的字节.

线程2正在读取125271到133463之间的字节.

线程3正在读取201390到209582之间的字节.

线程2正在读取133463到136295之间的字节.

线程3正在读取209582到217774之间的字节.

线程3正在读取217774到225966之间的字节.

线程1正在读取0到8192之间的字节.

线程3正在读取225966到234118之间的字节.

线程2正在读取136295到139191之间的字节.

线程2正在读取139191到144983之间的字节.

线程2正在读取144983到149327之间的字节.

线程2正在读取149327到152223之间的字节.

线程2正在读取152223到155119之间的字节.

线程2正在读取155119到163311之间的字节.

线程3正在读取234118到235566之间的字节.

线程3正在读取235566到243758之间的字节.

线程3正在读取243758到251950之间的字节.

线程3正在读取251950到260142之间的字节.

线程3正在读取260142到268334之间的字节.

线程3正在读取268334到276526之间的字节.

线程3正在读取276526到284718之间的字节.

线程3正在读取284718到292910之间的字节.

线程3正在读取292910到296382之间的字节.

线程3正在读取296382到302087之间的字节.

线程1正在读取8192到11885之间的字节.

线程2正在读取163311到171047之间的字节.

线程1正在读取11885到20077之间的字节.

线程2正在读取171047到179239之间的字节.

线程1正在读取20077到28269之间的字节.

线程2正在读取179239到187431之间的字节.

线程1正在读取28269到36461之间的字节.

线程2正在读取187431到195623之间的字节.

线程2正在读取195623到201390之间的字节.

线程1正在读取36461到44653之间的字节.

线程1正在读取44653到52845之间的字节.

线程1正在读取52845到61037之间的字节.

线程1正在读取61037到69229之间的字节.

线程1正在读取69229到77421之间的字节.

线程1正在读取77421到85613之间的字节.

线程1正在读取85613到93805之间的字节.

线程1正在读取93805到100695之间的字节.

-------------------------------

文件读写完毕。 总长度为302087个字节。 


你可能感兴趣的:(使用线程池,;多线程下载,;异步操作)