我的Java开发学习之旅------>Java多线程下载文件 实例

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

public class MulThreadDownload {
	public static void main(String[] args) throws Exception {
		String path = "http://192.168.1.100:8080/Hello/Big.exe";
		new MulThreadDownload().download(path, 3);
	}

	/**
	 * 下载文件
	 *
	 * @param path
	 *            网络文件路径
	 * @param threadSize
	 *            线程数
	 * @throws Exception
	 */
	private void download(String path, int threadSize) throws Exception {
		URL url = new URL(path);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("GET");
		connection.setConnectTimeout(5000);
		if (connection.getResponseCode() == 200) {
			int length = connection.getContentLength();// 获取网络文件长度
			File file = new File(getFileName(path));
			// 在本地生成一个长度与网络文件相同的文件
			RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
			accessFile.setLength(length);
			accessFile.close();

			// 计算每条线程负责下载的数据量
			int block = length % threadSize == 0 ? length / threadSize : length
					/ threadSize + 1;
			for (int threadId = 0; threadId < threadSize; threadId++) {
				new DownloadThread(threadId, block, url, file).start();
			}
		} else {
			System.out.println("download fail");
		}
	}

	private class DownloadThread extends Thread {

		private int threadId;
		private int block;
		private URL url;
		private File file;

		public DownloadThread(int threadId, int block, URL url, File file) {
			this.threadId = threadId;
			this.block = block;
			this.url = url;
			this.file = file;
		}

		@Override
		public void run() {
			int start = threadId * block; // 计算该线程从网络文件什么位置开始下载
			int end = (threadId + 1) * block - 1; // 计算下载到网络文件什么位置结束
			try {
				RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
				accessFile.seek(start);  //从start开始

				HttpURLConnection connection = (HttpURLConnection) url
						.openConnection();
				connection.setRequestMethod("GET");
				connection.setConnectTimeout(5000);
				//设置获取资源数据的范围,从start到end
				connection.setRequestProperty("Range", "bytes=" + start + "-"
						+ end);
				//注意多线程下载状态码是 206  不是200
				if (connection.getResponseCode() == 206) {
					InputStream inputStream = connection.getInputStream();
					byte[] buffer = new byte[1024];
					int len = 0;
					while ((len = inputStream.read(buffer)) != -1) {
						accessFile.write(buffer, 0, len);
					}
					accessFile.close();
					inputStream.close();
				}
				System.out.println("第" + (threadId + 1) + "条线程已经下载完成");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取文件名称
	 *
	 * @param path
	 *            网络文件路径
	 * @return
	 */
	private String getFileName(String path) {
		return path.substring(path.lastIndexOf("/") + 1);
	}
}

==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

==================================================================================================

时间: 2024-10-30 06:39:19

我的Java开发学习之旅------&gt;Java多线程下载文件 实例的相关文章

我的Java开发学习之旅------&amp;gt;Java经典面试题

摘自张孝祥itcast 从享受生活的角度上来说:"程序员并不是一种最好的职业,我认为两种人可以做程序员,第一,你不做程序员,你就没有什么工作可做,或者说是即使有可以做的工作但是你非常不愿意去做:第二,你非常痴迷和爱好程序,并且在这方面有一些天赋和优势.程序员的结局也是有两种:第一,默默退休,第二以程序员为起点或跳板,注意积累,跟对了好的老板或团队,找到和很好的搭档自己创业,成为IT金领和富翁." 人们在时间面前是平等的,吾生也有涯,所以,你的经验更丰富点,那不算什么,经验是用时间积累的

我的Java开发学习之旅------&amp;gt;Java双重检查锁定及单例模式详解(转)

简介:          所有的编程语言都有一些共用的习语.了解和使用一些习语很有用,程序员们花费宝贵的时间来创建.学习和实现这些习语.问题是,稍后经过证明,一些习语并不完全如其所声称的那样,或者仅仅是与描述的功能不符.在 Java 编程语言中,双重检查锁定就是这样的一个绝不应该使用的习语.在本文中,Peter Haggar 介绍了双重检查锁定习语的渊源,开发它的原因和它失效的原因.         单例创建模式是一个通用的编程习语.和多线程一起使用时,必需使用某种类型的同步.在努力创建更有效的

我的Java开发学习之旅------&amp;gt;Java字符编码解析

Java开发中,常常会遇到乱码的问题,一旦遇到这种问题,常常就很扯蛋,每个人都不愿意承认是自己的代码有问题.其实编码问题并没有那么神秘,那么不可捉摸,搞清Java的编码本质过程就真相大白了.               其实,编码问题存在两个方面:JVM之内和JVM之外.   1.Java文件编译后形成class 这里Java文件的编码可能有多种多样,但Java编译器会自动将这些编码按照Java文件的编码格式正确读取后产生class文件,这里的class文件编码是Unicode编码(具体说是UT

我的Java开发学习之旅------&amp;gt;Java ClassLoader解析一(转)

jvm classLoader architecture: Bootstrap ClassLoader/启动类加载器  主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. Extension ClassLoader/扩展类加载器  主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作. System ClassLoader/系统类加载器  主要负责java -c

我的Java开发学习之旅------&amp;gt;Java ClassLoader解析二(转)

一.什么是ClassLoader?          大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常.而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需

我的Java开发学习之旅------&amp;gt;JAVA IO 设计模式彻底分析

本文转载于网络. 一.引子(概括地介绍Java的IO) 无论是哪种编程语言,输入跟输出都是重要的一部分,Java也不例外,而且Java将输入/输出的功能和使用范畴做了很大的扩充.它采用了流的 机制来实现输入/输出,所谓流,就是数据的有序排列,而流可以是从某个源(称为流源或Source of Stream)出来,到某个目的地(称为流汇或Sink of Stream)去的.由流的方向,可以分成输入流和输出流,一个程序从输入流读取数据向输出流写数据. 如,一个程序可以用FileInputStream类

我的Java开发学习之旅------&amp;gt;Java使用ObjectOutputStream和ObjectInputStream序列号对象报java.io.EOFException异常的解决方法

今天用ObjectOutputStream和ObjectInputStream进行对象序列化话操作的时候,报了java.io.EOFException异常. 异常代码如下: java.io.EOFException at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2554) at java.io.ObjectInputStream.readObject0(ObjectInputSt

我的Java开发学习之旅------&amp;gt;Java NIO 报java.nio.charset.MalformedInputException: Input length = 1异常

今天在使用Java NIO的Channel和Buffer进行文件操作时候,报了java.nio.charset.MalformedInputException: Input length = 1异常,具体如下: java.nio.charset.MalformedInputException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:260) at java.nio.char

我的Java开发学习之旅------&amp;gt;Java利用Comparator接口对多个排序条件进行处理

一需求 二实现Comparator接口 三验证排序结果 验证第一条件首先按级别排序级别最高的排在前面 验证第二条如果级别相等那么按工资排序工资高的排在前面 验证第三条如果工资相当则按入职年数排序入职时间最长的排在前面 附录javautilComparator接口源代码 一.需求 假设现在有个如此的需求:需要对一个这样的雇员列表进行排序,排序规则如下: 1.首先级别最高的排在前面, 2.如果级别相等,那么按工资排序,工资高的排在前面, 3.如果工资相当则按入职年数排序,入职时间最长的排在前面. 雇