多线程下载,以及断点的实现

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

/**
 * 多线程下载,以及断点下载的实现<br>
 * 其中有个不好的地方,<br>
 * 就是进度文件的保存的时候如果采用RandomAccessFile的方式进行保存的时候<br>
 * 虽然会将文件的进度时时的保存在进度文件中,<br>
 * 但是,经过实际的测试这样会大大的降低文件的下载的速度,<br>
 * 如果采用File和FileOutputStream的话虽然可以加快下载的速度<br>
 * 但是进度文件的时时写入会出现问题.<br>
 *
 * <br>
 * 目前我还没有找到很好的解决方式,如果大家有的话欢迎给我留言.
 *
 * @author MartinDong
 *
 */
public class Demo {
	// 定义线程个数
	public static int threadCount = 3;
	// 定义当前存货的线程个数
	public static int runningThread = 3;

	public static void main(String[] args) throws Exception {
		// 1,连接到服务器,获取一个文件,获取文件的大小跟服务器的文件一样的临时文件
		String path = "http://172.22.64.193:8080/test.exe";
		URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		// 设置超时
		conn.setConnectTimeout(5000);
		// 设置请求方式
		conn.setRequestMethod("GET");
		// 获取服务器的返回码
		int code = conn.getResponseCode();
		// 判断返回码
		if (code == 200) {
			// 获取返回的长度
			int length = conn.getContentLength();
			System.out.println("文件总长度:" + length);

			// 在客户端创建出一个跟服务器大小一致的临时文件
			RandomAccessFile raf = new RandomAccessFile("test.exe", "rwd");
			// 指定临时文件的大小
			raf.setLength(length);
			// 释放资源
			raf.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 DownlodeThread(path, threadId, startIndex, endIndex)
						.start();
			}
		}
	}

	/**
	 * 下载文件的子线程类,每一个线程下载对应位置文件数据
	 *
	 * @author MartinDong
	 *
	 */
	public static class DownlodeThread extends Thread {
		private String path;
		private int threadId;
		private int startIndex;
		private int endIndex;

		/**
		 *
		 * @param path
		 *            文件的下载路径
		 * @param threadId
		 *            线程id
		 * @param startIndex
		 *            线程开始的位置
		 * @param endIndex
		 *            线程结束的位置
		 */
		public DownlodeThread(String path, int threadId, int startIndex,
				int endIndex) {
			this.path = path;
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
		}

		@Override
		public void run() {
			try {
				// 检查是否存在下载历史的文件
				File tempFile = new File(threadId + ".txt");// =========================断点记录操作===============================
				if (tempFile.exists() && tempFile.length() > 0) {
					// 文件输入流
					FileInputStream fis = new FileInputStream(
							tempFile);
					// 中间变量,缓存的作用
					byte[] tempBuffer = new byte[1024];
					// 获取进度文件的数据大小
					int length = fis.read(tempBuffer);
					// 获取进度文件的数据
					String historyData = new String(tempBuffer, 0, length);
					// 将进度数据装换为整型
					int historyDataInt = Integer.parseInt(historyData);
					// 修改真正的下载位置
					startIndex = historyDataInt;
					fis.close();
				}// =========================断点记录操作===============================

				// 将地址转换为URL
				URL url = new URL(path);
				// 获取http连接
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				// 设置连接的请求方式
				conn.setRequestMethod("GET");
				// 重要:请求服务器下载部分的文件,指定文件的位置
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
						+ endIndex);

				System.out
						.println("线程:" + threadId + "真实开始的下载进度:" + startIndex);
				// 设置超时时间
				conn.setReadTimeout(5000);
				// 得到服务器的状态码,200表示请求的全部资源得到响应=== ok,206请求的部分资源得到响应=== ok
				int code = conn.getResponseCode();
				System.out.println("code:" + code);

				if (code == 206) {
					// 返回的是指定位置的文件流
					InputStream is = conn.getInputStream();
					// 创建一个临时的文件
					RandomAccessFile raf = new RandomAccessFile("test.exe",
							"rwd");
					// 移动指针,到指定的文件位置,
					raf.seek(startIndex);

					// 创建中间缓冲字节数组
					byte[] buffer = new byte[1024];
					// 读取文件的大小
					int length = 0;

					// 定义已经下载的数据长度,用作断点下载的记录=========================断点记录操作===============================
					int downlodeTotal = 0;
					// 循环写入
					while ((length = is.read(buffer)) != -1) {
						// 定义一个记录线程的记录文件=========================断点记录操作===============================
						RandomAccessFile historyFile = new RandomAccessFile(
								threadId + ".txt", "rwd");
						// 向文件中写入数据
						raf.write(buffer, 0, length);
						// 记录已经下载的文件长度
						downlodeTotal += length;
						// 将已经下载的文件长度和开始的读取位置相加,得到已经读取的文件位置
						historyFile.write((downlodeTotal + startIndex + "")
								.getBytes());
						historyFile.close();// =========================断点记录操作===============================
						System.out.println("线程:" + threadId + "已下载:"
								+ downlodeTotal);
					}
					is.close();
					raf.close();
					System.out.println("线程:" + threadId + "下载完毕............");

				} else {
					System.out.println("线程:" + threadId
							+ "下载失败请重新下载............");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				// 进行线程数量的变化操作
				runningThread--;
				// 如果当前存活的线程为0,执行进度文件统一销毁的操作
				if (runningThread == 0) {
					// 如果下载完毕,清除进度文件
					for (int threadIndex = 1; threadIndex <= threadCount; threadIndex++) {
						// 这里创建的是与线程文件对应的文件,文件名可以自定义,方便起见是采用的是线程的ID表示
						File temp = new File(threadIndex + ".txt");
						// 执行文件删除的操作
						temp.delete();
					}
					System.out.println("文件下载完毕,删除进度文件.............");
				}
			}
		}
	}

}

多线程下载,以及断点的实现,布布扣,bubuko.com

时间: 2024-10-26 04:31:38

多线程下载,以及断点的实现的相关文章

【原创】linux命令-Axel命令 - linux多线程下载 - 费元星 - 未来星开发团队

[费元星版权Q:9715234] Axel 是 Linux 下一个不错的HTTP/FTP高速下载工具.支持多线程下载.断点续[费元星版权Q:9715234]传,且可以从多个地址或者从一个地址的多个连接来下载同一个文件.适合网速不给力时多线程下载提高下载速度.在百度服务器上用20个线程跑,速度是, ,已经达到宽带的房顶!比wget快的超级多! 大家感觉一下 CentOS安装Axel: 目前yum源上没有Axel,我[费元星版权Q:9715234]们可以到http://pkgs.repoforge.

Android(十五)多线程下载包括断点续传

1.多线程下载,java程序 package com.itheima.download; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; imp

LINUX MAC Axel —— 一款比 wget 更强大的多线程下载工具

前言 最近使用 wget 下载百度云资源,速度比较缓慢,在朋友推荐多线程下载后发现 wget 其实仅仅是一个单线程下载工具,在面对文件时会显得十分鸡肋,并且有许多诟病,比如无断点重连等等功能. Axel 介绍 经过一些搜索后发现,有一个非常好用的下载工具名为 Axel ,和 wget 一样是命令行下的下载工具,但是支持多线程下载,断点重连等等强大的功能. 以下是 man 中它的英文介绍以及翻译: axel - light command line download accelerator. Ax

多线程下载文件,以及断点下载

一:前言 多线程下载文件,可能有的同学没有过多的听说过,但是断点下载肯定是听过的,也就是说像讯雷,哪怕你把电脑重启了,讯雷重新启动后也会接着原来的地方下载,那么这是怎么做到的呢? 二:代码示例 直接给出代码, 2.1.经典代码 两行经典的代码分别为: //设置下载的开始及结束位置 conn.setRequestProperty("Range", "bytes="+start+"-"+end+""); //设置读写的起点位置 R

【Java EE 学习第22天 文件下载】【单线程下载】【单线程断点下载】【多线程下载】

一.文件下载简述 1.使用浏览器从网页上下载文件,Servlet需要增加一些响应头信息 (1)response.setContentType("application/force-download"); (2)response.setContentLength(fis.available()); (3)response.setHeader("Content-Disposition","attachment;filename="+filename)

无废话Android之smartimageview使用、android多线程下载、显式意图激活另外一个activity,检查网络是否可用定位到网络的位置、隐式意图激活另外一个activity、隐式意图的配置,自定义隐式意图、在不同activity之间数据传递(5)

1.smartimageview使用 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

Android06_getpost提交_文件上传_多线程下载

提交数据有中文的话,一定要用URLEncoder进行编码 1,Get方式提交数据 1.1案例:发送QQ账号和密码 ①把信息通过网络请求发送到服务器 ②在服务端数据库查询账号密码是否存在 ③服务器返回具体的信息 1.1.1,Web端的实现 ①创建一个Servlet接收客户端请求 ②获取请求数据 ③封装成对象传入数据库中(因为主要是练习Android的网络请求,所以这里可以简化一下,直接判断两个数据是否相等) ④查询数据库返回结果 //通过response对象返回结果,response.getOut

mega多线程下载

20150204 现在只是看了个大概,对整个过程有了大致的理解,记录如下: mega多线程下载是mega存储的一部分,其中会有一些底层方法的支持,这些先不管,只是看明白是如何下载的. 可以加断点的文件:sources--no domain--其中的一个blob(js,最大的) 调用下载的语句:M.addDownload($.selected); dl_queue.push()---DownloadQueue.prototype.push dlIO = new dlMethod(dl_id, dl

Android 多线程下载原理剖析

今天带来一个多线程下载的 例子.先看一下效果,点击 下载 开始下载,同时显示下载进度,下载完成,变成程 安装,点击安装 提示 安装应用. 界面效果 这里写图片描述 线程池 ThreadPoolExecutor 在下面介绍实现下载原理的时候,我想尝试倒着来说,这样是否好理解一点? 我们都知道,下载助手,比如360, 百度的 手机助手,下载APP 的时候 ,都可以同时下载多个,所以,下载肯定是多线程的,所以我们就需要一个线程工具类 来管理我们的线程,这个工具类的核心,就是 线程池. 线程池Threa