Android--通过Http协议实现多线程下载

笔记摘要:

      主要介绍多线程的下载的实现原理,每段线程从不同位置进行文件的下载,其中对于文件的分段下载,主要使用到了随机读写文件类:RandomAccessFile,

       这里通过示例进行演示


一、多线程下载原理

1、得到网络文件的长度,然后在本地生成一个与它长度相等的本地文件,

2、需要计算每天线程的数据下载量,公式如下:

    假设使用N条线程下载,文件的长度为length

    int block = 文件长度%N==0 ? 文件长度/N : 文件长度/N+1

3、开启多天线程分别从网络文件的不同位置下载数据,并从本地相同位置写入数据,所以要计算出每条线程从网络文件的什么位置开始下载数据,到什么位置结束。

    起始位置:int start = threadid*block

    结束位置:int end = (threadid+1)*block-1

    当所有线程下载完成后,文件下载成功。


这里需要进行两类请求:

1、对需要下载文件时进行请求

2、每个线程进行下载时都要对自己所要下载的区域进行请求


注意:多线程下载请求成功的状态码是206


二、代码实现:


出现的问题:

    在DownloadThread中读取时,使用了read,而不是read(buf),导致连接时间超时或连接重置


创建一个web服务,并提供一个文件用于下载,这里创建的是名为web的服务器,并提供“foobar.exe”下载


多线程下载的业务类

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

public class MulThreadDownload {

	public static void main(String[] args) {
		String path = "http://10.1.8.137:8080/web/foobar.exe";
		try {
			new MulThreadDownload().download(path, 3);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void download(String path,int threadsize) throws IOException {
		URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(50000);
		conn.setRequestMethod("GET");
		System.out.println("donwload.....");
		if(conn.getResponseCode()==200){
			int length = conn.getContentLength();//获取文件的长度
			File file = new File(getFilename(path));
			//元数据:时间、作者等
			//为避免数据的丢失,以读写方式打开文件,模式为:”rwd",当调用write方法时,对每个更新都写入到底层存储设备
			RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");//在本地生成一个长度相等的文件
			accessFile.setLength(length);
			accessFile.close();
			
			//计算每条线程负责下载的数据量
			int block = length%threadsize==0 ? length/threadsize : length/threadsize+1;
			for(int threadid=0;threadid<threadsize;threadid++){
				new DownloadThread(threadid,block,url,file).start();
			}
		}else{
			System.out.println("下载失败!");
		}
	}

	private String getFilename(String path) {
		
		return path.substring(path.lastIndexOf("/")+1);
	}

}


多线程下载线程类:实现每个线程下载指定区域的文件

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

public class DownloadThread extends Thread{
	private int threadid;
	private int block;
	private URL url;
	private File file;
	
	@Override
	public void run() {
		int start = threadid*block;//计算该线程在网络文件的起始下载位置
		int end = (threadid+1)*block-1;//计算该线程从网络文件的结束下载位置
		try {
			RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
			accessFile.seek(start);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setReadTimeout(5000);
			conn.setRequestMethod("GET");
			
			conn.setRequestProperty("Range","bytes="+start+"-"+end);//发送下载网络文件某一个区域的请求
			if(conn.getResponseCode()==206){    //区域下载请求成功的状态码为206
				InputStream inStream = conn.getInputStream();
				byte[] buf = new byte[1024];
				int len = 0;
				while((len = inStream.read(buf))!=-1){    //这里错误调用了read(),导致连接超时或连接重置
					accessFile.write(buf,0,len);
				}
				accessFile.close();
				inStream.close();
			}
			System.out.println("第"+(threadid+1)+"线程已经下载完成");
		} catch (Exception e) {
			e.printStackTrace();
		}
	
	}

	public DownloadThread(int threadid, int block, URL url, File file) {
		this.block = block;
		this.file = file;
		this.threadid = threadid;
		this.url = url;
	}
	
}


posted @ 2013-01-21 19:57  积小流,成江海  阅读(446)  评论(0编辑  收藏  举报