zoukankan      html  css  js  c++  java
  • URL 多线程下载

    该资源来源于李刚老师的疯狂JAVA讲义

    InutStream openStream():打开与此URL链接,并返回一个用于读取该URL资源的InputStream.

    提供的openStream()可以读取该URL资源的InputStream,通过该 方法可以非常方便的读取远程资源--甚至实现多线程下载。程序如下:

    package com.net;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    
    /**
     * 多线程下载
     * @author yulei
     *
     */
    
    //定义下载从start到end 的内容的线程
    class DownThread extends Thread{
    	//定义字节数组(取水的竹筒)的长度
    	private final int BUF_LEN=32;
    	//定义下载的起始点
    	private long start;
    	//定义下载的结束点
    	private long end;
    	//下载资源对应的输入流
    	private InputStream is;
    	//将下载的字节输出到raf中
    	private RandomAccessFile raf;
    	//构造器,传入输入流,输出流和下载起始点、结束点
    	public DownThread(long start,long end ,InputStream is ,RandomAccessFile raf){
    		//输出改线程负责下载的字节位置
    		System.out.println(start+"---->"+end);
    		this.start=start;
    		this.end=end;
    		this.is=is;
    		this.raf=raf;
    	}
    	
    	public void run(){
    		try {
    			is.skip(start);
    			raf.seek(start);
    			//定义读取输入流内容的缓存数组
    			byte[] buff=new byte[BUF_LEN];
    			//本线程负责下载资源的大小
    			long contentLen=end-start;
    			//定义最多需要读取几次就可以完成本线程的下载
    			long times=contentLen/BUF_LEN+4;
    			//实际读取的字节数
    			int hasRead=0;
    			for (int i=0;i<times;i++){
    				hasRead=is.read(buff);
    				//如果读取的字节数小于0,则退出循环!
    				if(hasRead<0){
    					break;
    				}
    				raf.write(buff, 0, hasRead);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		//使用finally块来关闭当前线程的输入流、输出流
    		finally {
    			try {
    				  if(is!=null){
    					  is.close(); 
    				  }
    				  if(raf!=null){
    					  raf.close();
    				  }
    			} catch (Exception e2) {
    				e2.printStackTrace();
    			}
    		}
    	}
    }
    
    public class MutilDown {
     public static void main(String[] args) {
    	 
    	 final int DOWN_TREAD_NUM=4;
    	 final String OUT_FILE_NAME="down.jpg";
    	 InputStream[] isArr=new InputStream[DOWN_TREAD_NUM];
    	 RandomAccessFile[] outArr=new RandomAccessFile[DOWN_TREAD_NUM];
    	 try {
    		  //创建一个URL对象
    		  URL url=new URL("http://www.baidu.com/img/bd_logo1.png");
    		  //以此URL对象打开一个输入流
    		  isArr[0]=url.openStream();
    		  long fileLen=getFileLength(url);
    		  System.out.println("网路资源的大小:"+fileLen);
    		  //以输出文件名创建第一个RandomAccessFile输出流
    		  outArr[0]=new RandomAccessFile(OUT_FILE_NAME, "rw");
    		  //创建一个与下载资源相同大小的空文件
    		  for (int i=0;i<fileLen;i++){
    			  outArr[0].write(0);
    		  }
    		  //每线程应该下载的字节数
    		  long numPerThread=fileLen/DOWN_TREAD_NUM;
    		  //整个下载资源整除后剩下的余数
    		  long left=fileLen%DOWN_TREAD_NUM;
    		  for(int i=0;i<DOWN_TREAD_NUM;i++){
    			  //为每个线程打开一个输入流、一个RandomAccessFile对象
    			  //让每个线程分别负责下载资源的不同部分
    			  if(i!=0){ //上面已经初始化一次了,所以这里写i!=0 即可
    				  //以URL打开多个输入流
    				  isArr[i]=url.openStream();
    				  //以指定输出文件创建多个RandomAccessFile对象
    				  outArr[i]=new RandomAccessFile(OUT_FILE_NAME,"rw");
    			  }
    			  
    			  //分别启动多个线程下载网路资源
    			  if(i==DOWN_TREAD_NUM-1){
    				  //最后一个线程下载指定numPerThread+left个字节
    				  new DownThread(i*numPerThread, (i+1)*numPerThread, isArr[i], outArr[i]).start();
    			  }else{
    				  //每个线程负责下载一定的numPerThread个字节
    				  new DownThread(i*numPerThread,(i+1)*numPerThread,isArr[i], outArr[i]).start();
    			  }
    			  
    		  }
    		  
    	} catch (MalformedURLException e) {
    		e.printStackTrace();
    	} catch (IOException e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	}
    }	
     
     //定义获取指定网路资源长度的方法
     
     public static long getFileLength(URL url) throws IOException{
    	 long lenth=0;
    	 //打开该URL对应的URLConnection
    	 URLConnection con=url.openConnection();
    	 //获取连接URL资源的长度
    	 long size =con.getContentLength();
    	 System.out.println("网路资源SIZE 的长度:"+size);
    	 lenth=size;
    	return lenth;
     }
    
     
    }
    

    上面程序定义了DownTread线程类,该线程从InputStream中读取从start开始,到end结束的所有字节数据,并写入RandomAccessFile对象。这个DownThread线程类的run就是一个简单的输入、输出实现。

    程序中MutilDown类中的main方法负责按如下步骤来实现多线程下载:

    1 、创建URL对象。

    2、获取指定URL对象所指向资源的大小(由getFIleLength方法实现),此处用到了URLConnection类,该类代表JAVA应用程序和URL之间的通信链接。

    3、在本地磁盘上创建一个与网路资源相同大小的空文件。

    4、计算每条线程应该下载网路资源的哪个部分(从哪个字节开始,到哪个字节结束)。

    5、依次创建、启动多条线程来下载网路资源的指定部分。

  • 相关阅读:
    JQuery高级
    Filter&Listener
    关于用户信息的一个综合案例
    JSP,EL和JSTL
    Cookie和Session
    Request和Response
    Servlet和HTTP请求协议
    Tomcat
    xml
    数组模拟堆
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300351.html
Copyright © 2011-2022 走看看