`
xuyuanshuaaa
  • 浏览: 395934 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

java多线程文件下载

 
阅读更多
1、DownloadManager类
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class DownloadManager implements Runnable {
	// 保存路径
	private String savePath;
	// 总的下载线程数
	private int threadNum;
	// 下载的链接地址
	private String urlFile;
	// 是否下载开始
	private boolean isStarted;
	// 用于监视何时合并文件存放Thread的list
	private List<DownloadThread> downloadList = new ArrayList<DownloadThread>();

	public DownloadManager(String savePath, int threadNum, String urlFile) {
		super();
		this.savePath = savePath;
		this.threadNum = threadNum;
		this.urlFile = urlFile;
	}

	// 最终调用线程下载。本线程中调用分线程。
	public void action() {
		new Thread(this).start();
	}

	public void run() {
		long t1 = System.currentTimeMillis();
		System.out.println(t1);
		// 如果没有下载 , 就开始 , 并且将已经下载的变量值设为true
		if (!isStarted) {
			startDownload();
			isStarted = true;
		}
		while (true) {
			// 初始化认为所有线程下载完成,逐个检查
			boolean finish = true;
			// 如果有任何一个没完成,说明下载没完成,不能合并文件
			for (DownloadThread thread : downloadList) {
				if (!thread.isFinish()) {
					finish = false;
					break;
				}
			}
			// 全部下载完成才为真
			if (finish) {
				// 合并文件
				mergeFiles();
				// 跳出循环 , 下载结束
				break;
			}
			// 休息一会 , 减少cpu消耗
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		long t2 = System.currentTimeMillis();
		System.out.println(t2);
		 System.out.println("下载用时:" + (t2 -t1));
	}

	public void startDownload() {
		// 得到每个线程开始值 , 下载字节数大小
		int[][] posAndLength = getPosAndLength();
		// 根据下载信息创建每个下载线程,并且启动他们。
		for (int i = 0; i < posAndLength.length; i++) {
			int pos = posAndLength[i][0];
			int length = posAndLength[i][1];
			DownloadThread downloadThread = new DownloadThread(i + 1, length,
					pos, savePath, urlFile);
			new Thread(downloadThread).start();
			downloadList.add(downloadThread);
		}
	}

	/**
	 * 获得文件大小
	 * 
	 * @return 文件大小
	 */
	public long getFileLength() {
		System.out.println("获得文件大小  start......");
		HttpURLConnection conn = null;
		long result = 0;
		try {
			URL url = new URL(urlFile);
			conn = (HttpURLConnection) url.openConnection();
			// 使用Content-Length头信息获得文件大小
			result = Long.parseLong(conn.getHeaderField("Content-Length"));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}
		System.out.println("获得文件大小  end......" + result);
		return result;
	}

	// 具体细节求出每个线程的开始位置和文件下载大小
	public int[][] getPosAndLength() {
		int[][] result = new int[threadNum][2];
		int fileLength = (int) getFileLength();
		int every = fileLength % threadNum == 0 ? fileLength / threadNum
				: fileLength / threadNum + 1;
		for (int i = 0; i < result.length; i++) {
			int length = 0;
			if (i != result.length - 1) {
				length = every;
			} else {
				length = fileLength - i * every;
			}
			result[i][0] = i * every;
			result[i][1] = length;
		}
		return result;
	}

	// 合并文件
	public void mergeFiles() {
		System.out.println("合并文件  start......");
		OutputStream out = null;
		try {
			out = new FileOutputStream(savePath);
			for (int i = 1; i <= threadNum; i++) {
				InputStream in = new FileInputStream(savePath + i);
				byte[] bytes = new byte[2048];
				int read = 0;
				while ((read = in.read(bytes)) != -1) {
					out.write(bytes, 0, read);
					out.flush();
				}
				if (in != null) {
					in.close();
					new File(savePath + i).delete();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("合并文件  end......");
	}

	public String getSavePath() {
		return savePath;
	}

	public void setSavePath(String savePath) {
		this.savePath = savePath;
	}

	public int getThreadNum() {
		return threadNum;
	}

	public void setThreadNum(int threadNum) {
		this.threadNum = threadNum;
	}

	public String getUrlFile() {
		return urlFile;
	}

	public void setUrlFile(String urlFile) {
		this.urlFile = urlFile;
	}

	public boolean isStarted() {
		return isStarted;
	}

	public void setStarted(boolean isStarted) {
		this.isStarted = isStarted;
	}

	public List<DownloadThread> getDownloadList() {
		return downloadList;
	}

	public void setDownloadList(List<DownloadThread> downloadList) {
		this.downloadList = downloadList;
	}
}

2、DownloadThread类
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class DownloadThread implements Runnable {
	// 当前第几个线程 , 用于给下载文件起名 file1 file2 file3 ...
	private int whichThread;
	// 监听单一线程下载是否完成
	private boolean isFinish;
	// 本线程要下载的文件字节数
	private int length;
	// 本线程向服务器发送请求时输入流的首位置
	private int startPosition;
	// 保存的路径
	private String savePath;
	// 要下载的文件 , 用于创建连接
	private String url;

	public void run() {
		HttpURLConnection conn = null;
		InputStream in = null;
		OutputStream out = null;
		try {
			System.out.println("正在执行的线程:" + whichThread);
			URL fileUrl = new URL(url);
			// 与服务器创建连接
			conn = (HttpURLConnection) fileUrl.openConnection();
			// 下载使用get请求
			conn.setRequestMethod("GET");
			// 告诉服务器 , 我是火狐 , 不要不让我下载。
			conn.setRequestProperty(
							"User-Agent",
							"Firefox Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3");
			// 这里是设置文件输入流的首位置
			conn.setRequestProperty("Range", "bytes=" + startPosition + "-");
			// 与服务器创建连接
			conn.connect();
			// 获得输入流
			in = conn.getInputStream();
			// 在硬盘上创建file1 , file2 , ...这样的文件 , 准备往里面写东西
			out = new FileOutputStream(savePath + whichThread);
			// 用于写入的字节数组
			byte[] bytes = new byte[4096];
			// 一共下载了多少字节
			int count = 0;
			// 单次读取的字节数
			int read = 0;
			while ((read = in.read(bytes)) != -1) {
				// 检查一下是不是下载到了本线程需要的长度
				if (length - count < bytes.length) {
					// 比如说本线程还需要900字节,但是已经读取1000
					// 字节,则用要本线程总下载长度减去
					// 已经下载的长度
					read = length - count;
				}
				// 将准确的字节写入输出流
				out.write(bytes, 0, read);
				// 已经下载的字节数加上本次循环字节数
				count = count + read;
				// 如果下载字节达到本线程所需要字节数,消除循环,
				// 停止下载
				if (count == length) {
					break;
				}
			}
			// 将监视变量设置为true
			isFinish = true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 最后进行输入、输出、连接的关闭
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (conn != null) {
				conn.disconnect();
			}
		}
	}

	public int getStartPosition() {
		return startPosition;
	}

	public void setStartPosition(int startPosition) {
		this.startPosition = startPosition;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public int getWhichThread() {
		return whichThread;
	}

	public void setWhichThread(int whichThread) {
		this.whichThread = whichThread;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

	public String getSavePath() {
		return savePath;
	}

	public void setSavePath(String savePath) {
		this.savePath = savePath;
	}

	public DownloadThread(int whichThread, int length, int startPosition,
			String savePath, String url) {
		super();
		this.whichThread = whichThread;
		this.length = length;
		this.startPosition = startPosition;
		this.savePath = savePath;
		this.url = url;
	}

	public DownloadThread() {
		super();
	}

	public boolean isFinish() {
		return isFinish;
	}

	public void setFinish(boolean isFinish) {
		this.isFinish = isFinish;
	}
}

3、TestDownload测试类
public class TestDownload {

	public static void main(String[] args) {
		DownloadManager downloadManager = new DownloadManager("d:/upload/09018417.zip" , 5 , "http://10.1.2.65:8080/cetvossFront/09018417.zip");
		downloadManager.action();
	}
}

转自:
http://ljlleo.iteye.com/blog/1397765
分享到:
评论

相关推荐

    Java多线程文件下载

    Java多线程文件下载是一种高效的下载策略,它通过将大文件分割成多个部分,然后创建多个线程分别下载这些部分,来实现并行下载。这种技术可以显著提高下载速度,尤其是在网络条件不稳定或者带宽有限的情况下。下面...

    Java多线程设计模式上传文件

    Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式...

    java多线程读取文件

    Java多线程读大文件 java多线程写文件:多线程往队列中写入数据

    Java多线程文件分片下载实现的示例代码

    Java多线程文件分片下载实现的示例代码 本文将详细介绍Java多线程文件分片下载的实现示例代码,通过示例代码,大家可以学习和理解多线程文件分片下载的技术难点和解决方案。 多线程下载的技术难点 ---------------...

    java多线程文件下载,将下载任务分片,每片一个线程下载

    综上所述,Java多线程文件下载是一种利用并发提升效率的技术,涉及到文件分片、线程池管理、任务提交、文件合并等多个步骤,需要综合运用Java的并发编程知识。正确实现后,可以显著改善大文件下载的体验。

    Java 多线程下载网站

    这个Java多线程下载网站项目结合了网络编程、HTML解析、文件操作等多个Java核心概念,对于提升Java程序员的全栈开发能力具有很高的实践价值。通过学习和实践这个项目,开发者不仅可以掌握多线程下载的技巧,还能深入...

    java多线程URL方式下载单个大文件

    在Java编程中,多线程下载大文件是一种常见的优化策略,尤其对于网络资源如文件或图片的下载。这种策略能够利用多核处理器的优势,通过并发处理来提高下载速度。本篇将详细介绍如何使用Java实现基于URL的单个大文件...

    java多线程下载文件

    ### Java多线程断点下载文件:关键技术与实现 在当今高速互联网环境下,高效的数据传输技术变得至关重要。Java多线程断点续传文件下载技术就是一种能够显著提高下载速度和稳定性的方法。本文将深入解析Java多线程...

    java多线程简单下载器

    【Java多线程简单下载器】是一个初学者的编程作业,虽然代码可能较为混乱,但其核心功能已经实现,即通过多线程技术进行文件的下载。在Java中,多线程是并发处理的重要手段,它允许多个任务在同一时间执行,从而提高...

    Java多线程下载器

    Java多线程下载器是一种利用Java编程语言实现的高效文件下载工具,它通过将大文件分割成多个部分并同时下载,显著提高了下载速度。在Java中实现多线程下载器涉及许多关键概念和技术,包括线程、并发控制、网络I/O...

    java 多线程下载 (单文件)

    Java多线程下载技术主要应用于提高大文件下载的效率,通过将文件分割成多个部分,同时启动多个线程分别下载这些部分,从而实现并行下载,加快下载速度。以下是对这个主题的详细解释: 1. **Java多线程基础**: 在...

    java多线程下载器

    Java多线程下载器是一种利用Java编程语言实现的高效文件下载工具,它通过将大文件分割成多个小部分,然后创建多个线程同时下载这些部分,以提高下载速度。这种技术在处理大文件或者网络带宽有限的情况下尤其有用,...

    Java 多线程断点下载文件

    Java多线程断点下载文件是一种高效的文件下载方式,它允许在下载过程中暂停并从上次停止的地方继续,尤其适用于大文件下载。以下是实现这一功能的关键知识点: 1. **获取文件信息**: - 使用`java.net.URL`和`java...

    Java多线程下载

    Java多线程下载技术是Java开发中用于提升大文件下载效率的一种常见方法。在传统的单线程下载过程中,网络请求可能会因为各种原因中断,如网络波动、服务器问题或用户操作等,这会导致需要从头开始下载,浪费时间和...

    Java多线程断点下载Sample

    在这个“Java多线程断点下载Sample”示例中,我们将深入探讨如何利用Java的多线程特性来实现文件的断点续传下载,并结合进度条展示下载进度。 首先,我们需要理解什么是多线程。在单线程环境中,程序的执行顺序是...

    java多线程断点下载

    Java多线程断点下载是网络编程中一个实用的技术,尤其在处理大文件时能显著提升用户体验。在本文中,我们将深入探讨这个主题,讲解如何使用Java实现多线程和断点续传功能。 首先,我们需要理解什么是多线程。在...

    java多线程文件传输

    Java多线程文件传输是Java编程中一个重要的实践领域,特别是在大数据处理、网络通信和分布式系统中。在Java中,多线程可以提高程序的执行效率,尤其在处理并发任务时,如大文件的上传、下载和传输。下面将详细探讨...

    Java 利用多线程实现文件的分片下载

    刚学完多线程和线程池,以及线程爱好者。 使用场景及目标: 大文件的快速下载,经测试在100M带宽的网络下,下载一个40M的文件,不超过两秒钟,当然还得根据自己电脑的配置来讲。 其他说明: 文件如果特别小,而...

    java 多线程操作数据库

    ### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...

    java多线程的讲解和实战

    Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...

Global site tag (gtag.js) - Google Analytics