`
zqb666kkk
  • 浏览: 726105 次
  • 性别: Icon_minigender_1
  • 来自: 宁波
社区版块
存档分类
最新评论

多线程下载文件

    博客分类:
  • java
 
阅读更多
package mutiDownload;

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

/**
 * 多线程下载文件
 * @author Administrator
 *
 */
public class Demo {

	
	public final static int threadcount=3;
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		
		//获取服务器上的文件长度,在本地创建一个和服务器上的文件一样大的临时文件
		String pathString="http://192.168.1.84:8091/androidServer/test.mkv";
		URL url=new URL(pathString);
		HttpURLConnection connection=(HttpURLConnection) url.openConnection();
		connection.setConnectTimeout(5000);
		connection.setRequestMethod("GET");
		int code=connection.getResponseCode();
		if(code==200){	//请求成功
			int length=connection.getContentLength();
			System.out.println("文件长度:"+length);
			RandomAccessFile ref=new RandomAccessFile("test.mkv","rwd");
			//指定创建的临时文件的长度
			ref.setLength(length);
			ref.close();
			
			int blocksize=length/threadcount;
			for(int threadId=1;threadId<=threadcount;threadId++){
				int startIndex=(threadId-1)*blocksize;	//线程开始位置
				int endIndex=threadId*blocksize-1;
				if(threadId==threadcount){
					endIndex=length;
				}
				System.out.println("线程"+threadId+"下载---"+startIndex+"-->"+endIndex);
				new Downhread(threadId, startIndex, endIndex, pathString).start();;
				
			}
		}else{
			System.out.println("服务器错误");
		}
		
	}
	
	/**
	 * 下载文件子线程
	 * @author Administrator
	 *
	 */
	public static class Downhread  extends Thread {
		private int threadId;
		private int startIndex;
		private int endIndex;
		private String path;
		
		

		/**
		 * 
		 * @param threadId	线程id
		 * @param startIndex	线程下载的开始位置
		 * @param endIndex
		 * @param path	下载文件在服务器上的位置
		 */
		public Downhread(int threadId, int startIndex, int endIndex, String path) {
			super();
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.path = path;
		}




		@Override
		public void run() {
			// TODO Auto-generated method stub
			//super.run();
			try {
				URL url=new URL(path);
				HttpURLConnection connection=(HttpURLConnection) url.openConnection();
				connection.setConnectTimeout(5000);
				connection.setRequestMethod("GET");
				connection.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
				int code=connection.getResponseCode();
				System.out.println("code:"+code);
//				if(code==200){	//请求成功
//					
//				}
				InputStream is=connection.getInputStream();
				RandomAccessFile raf=new RandomAccessFile("test.mkv","rwd");
				//写文件的时候指定从哪个位置开始写
				raf.seek(startIndex);
				
				int len=0;
				byte [] buffer=new byte[1024];
				while((len=is.read(buffer))!=-1){
					raf.write(buffer, 0, len);
					
				}
				is.close();
				raf.close();
				System.out.println("线程:"+threadId+"下载完毕了...");
				
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
1
1
分享到:
评论
4 楼 zqb666kkk 2014-09-23  
liujiafei_2007 写道
RandomAccessFile ref=new RandomAccessFile("test.mkv","rwd"); 
//指定创建的临时文件的长度 
ref.setLength(length); 
ref.close();
你好,请问main方法中的这三行有什么作用呢?




RandomAccessFile("test.mkv","rwd");   //

RandomAccessFile

public RandomAccessFile(File file,
                        String mode)
                 throws FileNotFoundException
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。将创建一个新的 FileDescriptor 对象来表示此文件的连接。
mode 参数指定用以打开文件的访问模式。允许的值及其含意为:



含意

"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd"  打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
"rws" 和 "rwd" 模式的工作方式极其类似 FileChannel 类的 force(boolean) 方法,分别传递 true 和 false 参数,除非它们始终应用于每个 I/O 操作,并因此通常更为高效。如果该文件位于本地存储设备上,那么当返回此类的一个方法的调用时,可以保证由该调用对此文件所做的所有更改均被写入该设备。这对确保在系统崩溃时不会丢失重要信息特别有用。如果该文件不在本地设备上,则无法提供这样的保证。
"rwd" 模式可用于减少执行的 I/O 操作数量。使用 "rwd" 仅要求更新要写入存储的文件的内容;使用 "rws" 要求更新要写入的文件内容及其元数据,这通常要求至少一个以上的低级别 I/O 操作。

如果存在安全管理器,则使用 file 参数的路径名作为其参数调用它的 checkRead 方法,以查看是否允许对该文件进行读取访问。如果该模式允许写入,那么还使用该路径参数调用该安全管理器的 checkWrite 方法,以查看是否允许对该文件进行写入访问。

                             -----引自jdk 1.6api

其实上面这三个主要是迅雷的下载原理  就是下载之前 先在本地创建一个和服务器上一样大的临时文件  并且指定 随机访问文件的操作权限 为 rwd 然后做完这一步后关闭此随机访问文件流并释放与该流关联的所有系统资源
3 楼 zqb666kkk 2014-09-23  
cywhoyi 写道
挺好的多线程案例,我想询问以下几个问题,如果不对之处,望谅解
1.其实这样length分开略显不公平,譬如中华人民共和国1234567,其实前者thread的io消耗更大
2.看得出来是用来爬数据用,因为主线和子线都是同步,是否对于cpu\memory要求很高,是否模拟用异步任务来
3.每个线程其实都是独立分开的,在写文件时候,如何保证是append的?



下载的时候三个线程 各自负责一个区域   三个区域拼成一个完整的文件
2 楼 cywhoyi 2014-09-22  
挺好的多线程案例,我想询问以下几个问题,如果不对之处,望谅解
1.其实这样length分开略显不公平,譬如中华人民共和国1234567,其实前者thread的io消耗更大
2.看得出来是用来爬数据用,因为主线和子线都是同步,是否对于cpu\memory要求很高,是否模拟用异步任务来
3.每个线程其实都是独立分开的,在写文件时候,如何保证是append的?
1 楼 liujiafei_2007 2014-09-22  
RandomAccessFile ref=new RandomAccessFile("test.mkv","rwd"); 
//指定创建的临时文件的长度 
ref.setLength(length); 
ref.close();
你好,请问main方法中的这三行有什么作用呢?

相关推荐

Global site tag (gtag.js) - Google Analytics