`

多线程下载简单实现

 
阅读更多
多线程下载简单实现


1、多线程下载原理
   将网络上待下载的文件,划分为几段,然后对应开几条线程分别对应划分好的段,分别进行下载。如下图:


2、多线程文件下载注意点
   这里主要还是分段需注意下起始位置和终止位置。这里我们的处理是:
先取出文件的大小:size = con.getContentLength();然后再进行下面分段的长度测量:int block = size%threadNum==0?size/threadNum:size/threadNum+1;这样我们保证分成的几段长度加起来大于或等于待下载文件的长度。

下面是代码:
package org.hwq.multhreaddownload;

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

public class MulThreadDownload2 {
	//开启的线程数
	public static final int threadNum = 3;
	public void download() throws IOException{
		//下载文件的网络路径
		URL url = new URL("http://localhost:8080/Thunder.exe");
		//打开网络连接
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		//获取待下载文件的大小
		int remoteFileSize = con.getContentLength();
		//定义下载完成后保存的文件
		RandomAccessFile file = new RandomAccessFile("d:\\Thunder.exe","rwd");
		//将文件的长度设置成待下载文件的大小
		file.setLength(remoteFileSize);
		//将待下载文件分段
		int block = remoteFileSize%threadNum==0?remoteFileSize/threadNum:remoteFileSize/threadNum+1;
		//启动线程,开始下载
		for(int i=0;i<threadNum;i++){
			new MyThread(block*i,block,"d:\\Thunder.exe",url).start();
		}
	}
	class MyThread extends Thread{
		URL url;//待下载文件路径
		int start;//下载开始点
		int block;//分段的长度
		RandomAccessFile file;//下载后保存的文件
		MyThread(int start,int block,String file,URL url) throws FileNotFoundException{
			this.start = start;
			this.block = block;
			//这个地方需注意,必须让每条线程,独立开启文件,不然对同一个文件进行操作,会出导致出错
			this.file = new RandomAccessFile(file,"rwd");
			this.url = url;
		}
		public void run(){
			try {
				//重新分别打开下载路径
				HttpURLConnection con = (HttpURLConnection) url.openConnection();
				con.setRequestMethod("GET");
				//获取分段后要下载的数据
				con.setRequestProperty("Range", "bytes=" + start + "-" + (start+block-1));
				//获取待下载文件输入流
				InputStream in = con.getInputStream();
				//缓冲区
				byte[] b = new byte[1024];
				int len = -1;
				//将保存文件开始下载起点移到同待下载文件读取数据的起始点(不设置会出问题)
				file.seek(start);
				while((len = in.read(b))!=-1){
					//将下载的数据写入保存文件
					file.write(b, 0, len);
				}
				//关闭文件
				file.close();
				//关闭输入流
				in.close();
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) throws IOException {
		MulThreadDownload2 d = new MulThreadDownload2();
		d.download();
	}
}


过程中很悲催的不知道这个方法:
con.setRequestProperty("Range", "bytes=" + start + "-" + (start+block-1));

可以获得远程文件分段,结果自己写了个(其实是仿照InputStream源码的skip()方法),记录下来:
int block = size%threadNum==0?size/threadNum:size/threadNum+1;
		public int read(InputStream in,byte[] b){
			try{
				if(block==0)
					return -1;
				int c = in.read();
				if(c == -1)
					return -1;
				block--;
				b[0] = (byte) c;
				int i = 1;
				for(;i<b.length&&block>0;i++){
					c = in.read();
					if(c == -1)
						break;
					block--;
					b[i] = (byte) c;
				}
				return i;
			}catch (Exception e) {
				e.printStackTrace();
			}
			return -1;
		}


最后,有几个点不明白:
HttpURLConnection,URLConnection中的下面方法看不懂,希望有懂得的朋友讲解下
public String getHeaderField(String name) {
        return null;
    }
public String getHeaderFieldKey(int n) {
        return null;
    }
public String getHeaderField(int n) {
        return null;
    }
.......

为什么直接返回null了。但是程序还能执行下去。小弟实在不解啊。
  • 大小: 6.6 KB
分享到:
评论
2 楼 uuubd 2012-06-18  
listen1984 写道
HttpURLConnection是个abstract class,真正调用的是URLConnection中的方法。

另外千万不要用skip那个办法,那样的话不会节省时间,反而增加下载所需时间。

listen1984 写道
HttpURLConnection是个abstract class,真正调用的是URLConnection中的方法。

另外千万不要用skip那个办法,那样的话不会节省时间,反而增加下载所需时间。

这个有什么原因吗?想知道下。
1 楼 listen1984 2012-06-14  
HttpURLConnection是个abstract class,真正调用的是URLConnection中的方法。

另外千万不要用skip那个办法,那样的话不会节省时间,反而增加下载所需时间。

相关推荐

Global site tag (gtag.js) - Google Analytics