您的位置:首页 > 编程语言 > Java开发

Java中使用RandomAccessFile类实现多线程下载

2014-07-18 15:01 429 查看
多线程下载文件的注意点主要有:

1、确定每个线程下载的文件大小,用这种方法计算:

先获取整个文件的大小length,然后除以线程个数count得到每个线程下载的块大小为blockSize = length / count,每个线程的起始下载点为:startPos = blockSize * i,结束下载点为:endPos = blockSize * (i + 1) - 1,其中最后一个线程下载的结束点应该为文件末尾

2、随机访问文件RandomAccessFile类的使用方法,该类的实例化需要两个参数,第一个可以使一个文件File类,也可以是文件的path,String类,第二个参数代表文件写入的模式,可以为"r","rw","rws","rwd"之一

3、在每个线程中写文件的时候都需要实例化一个RandomAccessFile的实例,而不能重复使用同一个RandomAccessFile

4、在设置请求参数时,获取服务器的响应码会有所不同,如果请求的是一整个资源,则请求成功的响应码是200,若请求的是某个资源的部分时,请求成功返回的响应码是206,这一点需要注意,另外,在每个线程中下载一个文件的不同部分时,需要设置请求的头字段:conn.setRequestProperty("Range", "bytes=12345-13456");设置该头字段代表请求服务器资源的12345到13456这部分的内容

另外,在每个线程下载之前,需要将RandomAccessFile的实例的指针指向下载的开始点,使用如下方法:

raf.seek(startPos); 其中raf为RandomAccessFile类的对象,startPos为下载的开始点

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

public class Test {
	/**
	 * 文件下载的路径
	 */
	private static final String PATH = "http://localhost:8080/test.exe";
	/**
	 * 下载的线程个数
	 */
	private static final int COUNT = 3;
	/**
	 * 创建一个文件,将远程文件写入该文件
	 */
	private File f = new File("C:\\Users\\Administrator\\Desktop\\test.exe");
	
	public void download() throws Exception{
		URL url = new URL(PATH);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		//使用get请求
		conn.setRequestMethod("GET");
		//设置连接超时时间为5秒
		conn.setConnectTimeout(5000);
		//得到服务器返回的响应码
		int code = conn.getResponseCode();
		//响应码为200,代表请求资源成功(前提是请求整个资源,而不是资源的某一部分)
		if(code == 200){
			//得到文件的总大小
			int length = conn.getContentLength();
			//新建一个随机访问的文件
			RandomAccessFile raf = new RandomAccessFile(f, "rw");
			//第一个参数为文件类型,第二个参数为模式,可以为"r","rw","rws","rwd"
			raf = new RandomAccessFile(f, "rw");
			//设置随机文件的大小为服务器端文件的大小
			raf.setLength(length);
			System.out.println("文件总大小为:" + length);
			//计算每个线程下载的块的大小
			int blockSize = length / COUNT;
			for(int i = 0; i < COUNT; i++){
				//每个线程的起始下载点
				int startPos = blockSize * i;
				//每个线程的结束下载点
				int endPos = blockSize * (i + 1) - 1;
				//如果是最后一条线程,将其下载的终止点设为文件的终点
				if(i == COUNT){
					endPos = length;
				}
				System.out.println("线程" + i + "下载的部分为:" + startPos +"---" + endPos);
				//开启线程分别下载不同的部分
				new DownThread(i, startPos, endPos).start();
			}
		}
	}
	
	/**
	 * 下载文件的线程
	 * @author Administrator
	 *
	 */
	class DownThread extends Thread{
		//线程ID
		private int threadId;
		//线程下载的起始点
		private int startPos;
		//线程下载的结束点
		private int endPos;
		
		public DownThread(int threadId, int startPos, int endPos) {
			this.threadId = threadId;
			this.startPos = startPos;
			this.endPos = endPos;
		}

		@Override
		public void run(){
			try {
				URL url = new URL(PATH);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setRequestMethod("GET");
				//设置头部的参数,表示请求服务器资源的某一部分
				conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
				//设置了上面的头信息后,响应码为206代表请求资源成功,而不再是200
				int code = conn.getResponseCode();
				if(code == 206){
					InputStream is = conn.getInputStream();
					int hasRead = 0;
					byte[] buf = new byte[1024];
					//这里要注意新创建一个RandomAccessFile对象,而不能重复使用download方法中创建的
					RandomAccessFile raf = new RandomAccessFile(f, "rw");
					//将写文件的指针指向下载的起始点
					raf.seek(startPos);
					while((hasRead = is.read(buf)) > 0) {
						raf.write(buf, 0, hasRead);
					}
					is.close();
					System.out.println("线程" + threadId + "下载完毕...");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		try {
			new Test().download();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: