java线程实战:多线程下载(下)

多线程下载业务逻辑:html

一、URL请求获取下载文件的大小、计算每一个线程下载的起始位置java

二、RandomAccessFile类在存储空间占位,随机访问流在多线程下可同时读写文件api

三、开启线程,每一个线程负责下载文件的一部分,最后由随机访问流自动拼接文件,合成服务器

四、启动线程多线程

此项目须要了解java.io.RandomAccessFile、java.net .HttpURLConnection 的具体用法,在线API参考文档【http://tool.oschina.net/apidocs/apidoc?api=jdk-zh】dom

 

java.lang.Object
  java.net.URLConnection
      java.net.HttpURLConnection

重点:HttpURLConnection的父类URLConnection有个很是重要的 setRequestProperty() 方法,如下连接介绍了有关多线程下载,Range请求头的使用例子。ide

 

详情点击:【http://www.tuicool.com/articles/viUfMjY】ui

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;
 
public class Demo {
	//定义全局变量address
	static String address = "http://localhost:8080/ThreadDownloadServer/Blood.mp4";
	
	public static void main(String[] args) {
		//开启三个线程下载
		downloadFile(3);
	}
	
	/**
	 * 功能:计算每一个线程下载的起始位置,并执行下载。
	 * @param 线程数
	 */
	public static void downloadFile(int threadCount){
		
		try {
			URL url = new URL(address);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5000);
			conn.setReadTimeout(5000);
			//获取文件字节总大小
			int fileLength = conn.getContentLength();
			System.out.println("文件总大小:"+fileLength/1024/1024+"MB");
			int code = conn.getResponseCode();
			if (code == 200) {
				//分配每一个线程"平均"下载字节数
				int blockSize = fileLength/threadCount;
				//建立随机访问流,在本地为文件占位
				RandomAccessFile raf = new RandomAccessFile("Blood.mp4", "rw");
				//重点:假设文件只有10字节,分3个线程来下载,理解理解for循环代码
				for (int threadId = 0; threadId < threadCount; threadId++) {
					int startIndex = threadId*blockSize;
					int endIndex = (threadCount+1)*blockSize-1;
					if (threadId == threadCount) {
						endIndex = fileLength - 1;
					}
					//每循环一次,开启一个线程执行下载,别漏了start()。
					new ThreadDownload(threadId, startIndex, endIndex).start();;
				}
				conn.disconnect();
			}else{
				System.out.println("请求失败,服务器响应码:"+code);
			}
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 功能:开启线程下载,下载分配好的文件长度
	 * @author Administrator
	 * @param 线程ID,下载开始位置,结束位置,
	 */
	public static class ThreadDownload extends Thread{
		private int threadId;
		private int startIndex;
		private int endIndex;
		
		//构造方法接收3个参数初始化局部变量:线程ID、开始位置、结束位置
		public ThreadDownload(int threadId, int startIndex, int endIndex) {
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;	
		}
	
		@Override
		public void run(){
			try {
				URL url = new URL(address);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setReadTimeout(5000);
				System.out.println("线程"+threadId+"下载开始位置"+startIndex+" 结束位置:"+endIndex);
				
				//设置请求头,请求部分资源下载
				conn.setRequestProperty("Range", "bytes:"+startIndex+"-"+endIndex);
				//服务器响应码206表示请求部分资源成功
				if (conn.getResponseCode()==206) {
					InputStream inputStream = conn.getInputStream();
					RandomAccessFile raf = new RandomAccessFile(new File("Blood.mp4"), "rw");
					//查找写入开始位置
					raf.seek(startIndex);
					byte array[] = new byte[1024];
					int len = -1;
					while((len = inputStream.read(array))!=-1){
						raf.write(array, 0, len);
					}
					inputStream.close();
					raf.close();
					conn.disconnect();
				}else{
					System.out.println("服务器响应码:"+conn.getResponseCode());
				}
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

刷新项目,可见项目已生成:this

相关文章
相关标签/搜索