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

    我是新人,要喷请轻喷

    本来准备搞个java多线程下载器,在网上搜索一遍,全都是用的apache做的,我比较懒,就想如何才能不用apache搞一个出来,先搞了一个单线程的出来,用java自带的.net包搞定,成功完成了下载,废话不多说,下面上源码:


    /**
     * 完成单线程的下载任务
     */
    package net.meteor.download;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.net.URL;
    import java.net.URLConnection;
    
    
    /**
     * @author meteor
     * @email inwsy@hotmail.com
     * @version 1.8
     */
    public class Down {
    	public static void main(String[] args) throws Exception {
    		
    		//给出下载地址
    		URL url=new URL("http://codown.youdao.com/cidian/static/6.2/20140722/YoudaoDict.exe");
    		//建立通信连接
    		URLConnection urlcon=url.openConnection();
    		urlcon.connect();
    		
    		//打开输入流
    		InputStream in=urlcon.getInputStream();
    		
    		//获取文件
    		String filePath=url.getFile();
    		//返回“/”的位置索引
    		int i=filePath.lastIndexOf("/");
    		//得到文件名
    		String fileName=filePath.substring(i+1);
    		//打开输出流,创建接收文件
    		FileOutputStream out=new FileOutputStream("d:"+File.separator+fileName);
    		//将文件下载到本地
    		byte[] b=new byte[1024*1024];	
    		int len=0;
    		while((len=in.read(b))!=-1){
    			out.write(b, 0, len);	
    		}
    		
    	}
    }
    

    上面的注释已经写的很详细了,我就不多解释了,基本思想就是用URLConnection建立通信连接,然后用IO操作拿到文件,单线程的下载有了,其实变成多线程的就非常简单了,下面上多线程代码:


    /**
     * 完成多线程下载
     */
    package net.meteor.download;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    /**
     * @author meteor
     * @email inwsy@hotmail.com
     * @version 1.8
     */
    public class MyDownload {
    
    	public static String fileName;
    
    	public static void main(String[] args) throws Exception {
    		// 声明url
    		URL url = new URL("http://codown.youdao.com/cidian/static/6.2/20140722/YoudaoDict.exe");
    				//"http://pic.baomihua.com/photos/201109/m_6_634516970681718750_11187211.jpg");
    		// 获取链接
    		HttpURLConnection con = (HttpURLConnection) url.openConnection();
    		// 设置请求方式
    		con.setRequestMethod("GET");
    		// 获取请求头--文件长度
    		int len = con.getContentLength();// 获取文件长度用来计算每个线程的下载数据
    		System.out.println("文件长度为:[ "+len+" ]");
    		// 获取文件
    		String filePath = url.getFile();
    		// 返回“/”的位置索引
    		int i = filePath.lastIndexOf("/");
    		// 得到文件名
    		fileName = filePath.substring(i + 1);
    		// 在指定目录下创建一个同名同样大小的文件
    		RandomAccessFile file = new RandomAccessFile("d:" + File.separator
    				+ fileName, "rwd");
    		// 设置文件大小,占位
    		file.setLength(len);
    		// 定义线程个数
    		int num = 10;
    		// 计算每个线程应该下载的数据
    		int block = len / num == 0 ? len / num : len / num + 1;
    		System.out.println("每个线程下载的数据长度为:[ " + block+" ]");
    		// 运行线程,并计算线程的开始字节start和结束字节end
    		for (int j = 0; j < num; j++) {
    			int start = j * block;
    			int end = start + block;
    
    			System.out.println("第" + (j + 1) + "个字段 [ start:" + start + ","
    					+ "end:" + end + "," + "block:" + block + " ]");
    
    			MyDownloadThread m = new MyDownloadThread(start, end, url);
    			Thread t = new Thread(m);
    			t.start();
    		}
    
    	}
    }
    
    class MyDownloadThread implements Runnable {
    
    	private int start;
    	private int end;
    	private URL url;
    	InputStream in = null;
    	RandomAccessFile out = null;
    
    	public MyDownloadThread(int start, int end, URL url) {
    		super();
    		this.start = start;
    		this.end = end;
    		this.url = url;
    	}
    
    	public void run() {
    		// 开始下载
    		try {
    
    			HttpURLConnection con = (HttpURLConnection) url.openConnection();
    			// 设置分段下载的请求头
    			con.setRequestMethod("GET");
    
    			con.setRequestProperty("Range", "bytes=" + start + "-" + end);
    
    			// 开始下载,先判断206
    			if (con.getResponseCode() == 206) {// 访问成功,则返回代码206
    				// 声明输入流
    				in = con.getInputStream();
    				// 声明写文件对象,rwd是指将数据即时的写入到文件中,而不使用缓存区
    				out = new RandomAccessFile("d:" + File.separator
    						+ MyDownload.fileName, "rwd");
    
    				out.seek(start);
    
    				byte[] b = new byte[1024 * 1024*100];
    				int len = 0;
    				while ((len = in.read(b, start, end)) != -1) {
    					out.write(b, start, len);
    				}
    
    			}
    
    		} catch (Exception e) {
    
    			e.printStackTrace();
    		} finally {
    			try {
    				if (out != null)
    					out.close();
    				if (in != null)
    					in.close();
    			} catch (IOException e) {
    
    				e.printStackTrace();
    			}
    
    		}
    
    	}
    
    }
    

    上面url后面的两个地址是做测试用的,图片、exe等文件均可正常下载,出现的一个问题就是图片下载回来会有损坏的情况,经过一番思索,认为如果在一次通信可以秒掉的情况下,下载的文件是没有问题的,但是一次秒不掉中间会出现一些问题,为了让程序一次秒掉下载,我后面的byte数组改的比较大,可能部分朋友在做测试的时候会炸掉虚拟机,本人是在win8.1,JDK1.8做的测试,虚拟机正常工作。关于本次编程中间出现一些问题,欢迎前来讨论


    上面的源代码已经经过我重新编辑修改,找了个大神,已经把原来代码中出现的问题解决掉了,但是又引发了新的问题,在最后读入数据的时候为什么用read();就会出现错误,而改成read(byte[] b,int off,int len);这个方法以后就没有问题了,这俩方法还有什么区别么?求大神前来解答。。。

  • 相关阅读:
    Zuul的核心源码解析
    基于Sentinel的服务保护
    Sentinel
    windows进行配置转发
    Hystrix断路器
    服务熔断Hystrix高级
    微服务架构的高并发问题
    Feign的高级配置
    倒排序原理和实例
    云计算技术的产生、概念、原理、应用和前景
  • 原文地址:https://www.cnblogs.com/babycomeon/p/11109504.html
Copyright © 2011-2022 走看看