在Java中使用多线程结合断点续传实现一个简单的文件下载器

这篇博客介绍在android中使用多线程和断点续传实现一个简单的文件下载器

第一步:启动Tomcat服务器,将需要下载的文件部署到Tomcat服务器上


第二步:使用eclipse创建一个Java工程,并且在工程中添加下面的代码

package com.fyt.multidownload;

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

public class MultiDownload {

	//下载文件时开启的线程的个数
	static int ThreadCount = 3;
	
	//结束的线程的个数
	static int finishedThread = 0;
	
	//设置文件的下载地址
	static String path = "http://192.168.0.101:8080/app/genymotion-2.2.0-vbox.exe";
	
	public static void main(String[] args) {
		
		try {
			
			//将下载地址封装成Url对象
			URL url = new URL(path);
			
			//创建连接对象,此时未建立连接
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			
			//设置请求方式为get请求
			conn.setRequestMethod("GET");
			
			//设置连接超时
			conn.setConnectTimeout(5000);
			
			//设置读取超时
			conn.setReadTimeout(5000);
			
			//如果请求发送成功
			if(conn.getResponseCode() == 200) {
				
				//获得需要下载的文件的长度
				int length = conn.getContentLength();
				
				//创建File对象
				File file = new File("genymotion-2.2.0-vbox.exe");
				
				//生成临时文件(临时文件的大小为下载的文件的大小)
				RandomAccessFile raf = new RandomAccessFile(file, "rwd");
				
				//设置临时文件的大小
				raf.setLength(length);
				
				//关闭临时文件
				raf.close();
				
				//计算出每个线程应该下载多少字节
				int size = length / ThreadCount;
				
				//遍历创建好的线程
				for (int i = 0; i < ThreadCount; i++) {
					
					//计算线程下载的开始位置
					int startIndex = i * size;
					
					//计算线程下载的结束位置
					int endIndex = (i + 1) * size - 1;
					
					//如果是最后一个线程,那么结束位置写死
					if(i == ThreadCount - 1)
					{
						endIndex = length - 1;
					}
					
					//System.out.println("线程" + i + "的下载区间是:" + startIndex + "---" + endIndex);
				
					//创建下载线程
					//第一个参数:下载开始的位置
					//第二个参数:下载结束的位置
					//第三个参数:线程的Id
					DownLoadThread thread = new DownLoadThread(startIndex, endIndex, i);
					
					//启动下载线程
					thread.start();
				}
			}
		} catch (Exception e) {
			
			e.printStackTrace();
		}
	}
}


//创建一个继承自线程类的下载线程类
class DownLoadThread extends Thread {
	
	//线程下载的开始位置
	int startIndex;
	
	//线程下载的结束位置
	int endIndex;
	
	//线程的Id
	int threadId;
	
	//下载线程的构造方法
	public DownLoadThread(int startIndex, int endIndex, int threadId) {
		super();
		
		//设置线程下载的开始位置
		this.startIndex = startIndex;
		
		//设置线程下载的结束位置
		this.endIndex = endIndex;
		
		//设置线程的Id
		this.threadId = threadId;
	}

	//执行线程
	@Override
	public void run() {
		
		try {
			
			//创建保存下载进度的临时文件
			File progressFile = new File(threadId + ".txt");
			
			//如果进度临时文件存在
			if(progressFile.exists()) {
				
				//创建文件输入流
				FileInputStream fis = new FileInputStream(progressFile);
				
				//InputStreamReader:创建文件的输入流缓冲区对象
				//BufferedReader:创建文件的读取缓冲区对象
				BufferedReader br = new BufferedReader(new InputStreamReader(fis));
				
				//从进度临时文件中读取出上一次下载的总进度
				//然后与原本的开始位置相加,得到新的开始位置
				startIndex += Integer.parseInt(br.readLine());
				
				//关闭文件输入流
				fis.close();
			}
			
			//System.out.println("线程" + threadId + "的下载区间是:" + startIndex + "---" + endIndex);
			
			//使用URL对象封装下载文件的地址
			URL url = new URL(MultiDownload.path);
			
			//创建连接对象,此时未建立连接
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			
			//设置请求方式为get请求
			conn.setRequestMethod("GET");
			
			//设置连接超时
			conn.setConnectTimeout(5000);
			
			//设置读取超时
			conn.setReadTimeout(5000);
			
			//设置本次http请求所请求的数据的区间
			conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
			
			//请求部分数据
			//请求部分数据请求成功的响应码是206
			if(conn.getResponseCode() == 206) {
				
				//流里此时只有1/3原文件的数据
				//从响应中获取文件输入流
				InputStream is = conn.getInputStream();
				
				byte[] b = new byte[1024];
				int len = 0;
				int total = 0;
				
				//拿到临时文件的输出流
				File file = new File("genymotion-2.2.0-vbox.exe");
				
				//创建一个临时文件
				RandomAccessFile raf = new RandomAccessFile(file, "rwd");
				
				//把文件的写入位置移动至startIndex
				raf.seek(startIndex);
				
				while((len = is.read(b)) != -1) {
					
					//每次读取流里数据之后,同步把数据写入临时文件
					raf.write(b, 0, len);
					total += len;
					
					//System.out.println("线程" + threadId + "下载了" + total);
					
					//生成一个专门用来记录下载进度的临时文件
					RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
					
					//每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
					progressRaf.write((total + "").getBytes());
					
					//关闭进度临时文件
					progressRaf.close();
				}
				
				System.out.println("线程" + threadId + "下载完毕-------------------小志参上!");
				
				//关闭临时文件
				raf.close();
				
				//完成下载的线程的个数增加1
				MultiDownload.finishedThread++;
				
				//MultiDownload.path表示文件的下载地址
				synchronized (MultiDownload.path) {
					
					//如果三个下载线程都完成了下载任务
					if(MultiDownload.finishedThread == MultiDownload.ThreadCount) {
						
						//变量所有的下载线程所在的临时文件
						for (int i = 0; i < MultiDownload.ThreadCount; i++) {
							
							//获得下载线程下载的临时文件
							File f = new File(i + ".txt");
							
							//删除下载线程下载的临时文件
							f.delete();
						}
						
						//设置结束下载任务的下载线程的个数为0
						MultiDownload.finishedThread = 0;
					}
				}
			}
		} catch (Exception e) {
			
			e.printStackTrace();
		}
	}
}


第三步:执行程序,等到Console输出框中输出下图中所示的信息表示下载完成


此时在Java工程下可以看到多了一个genymotion-2.2.0-vbox.exe,表示下载成功了


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
注意: 如果下载后无法直接运行,则查看电脑是否有F盘,如果没有,可修改jar包的配置文件,将默认路径设置到其他盘,如C盘 说明: 1、这是myDownloader2.0自制下载,在1.0版本的基础上做了修正和功能上的扩展; 2、该“myDownloader2.0资源包”包括: (1)“myDownloader_2.0”文件夹,保存下载的源码, 其包含的doc文件夹存放的是有MyEclipse,javadoc生成的关于下载的API文档; (2)“jar包”文件夹,其myDownloader2.0.jar可以双击运行下载 (前提,电脑上装有JDK环境)。 3、可查看下载“功能介绍”了解下载具体功能。 功能介绍; 1、基本下载功能; 2、支持多任务多线程同时下载; 3、每个任务的线程数由用户在新建任务时自定义,缺省为5个线程; 4、任务下载过程可以点击“线程+”或“线程-”即时增减线程; 5、选择任务,可以在任务信息栏查看任务下载的信息; 6、对于正在下载和暂停的任务,可以再下载分块图示查看文件的分块下载情况; (灰色为未下载,绿色为下载,蓝色为完成) 7、若下载删除任务,则任务会先暂停,再被移动到垃圾箱; 8、整个界面分为三个视图:正在下载、已完成、垃圾箱; 9、下载过程可以暂停任务,点击开始可以继续下载; 10、对于失败的任务可以选择重新下载; 11、删除任务,如任务当前在正在下载或已完成,则任务将被删除到垃圾箱, 若在垃圾箱删除任务,则是彻底删除; 12、垃圾箱的任务可以恢复回正在下载或已下载视图; 13、可以点击“打开”,打开已完成的任务; 14、右键“打开文件夹”可以打开任务文件下载到的文件夹; 15、清空垃圾箱; 16、菜单栏“关于”,查看版本及作者等信息; 17、菜单栏“功能介绍”,查看下载的相关功能介绍; 18、程序退出前会自动暂停所有正在下载的任务,并保存到临时文件, 下次启动程序可以继续下载; 19、程序启动时,会在电脑检查创建myDownloader下载的相应文件夹, 用于保存临时文件和日志文件文件夹具体路径可以到myDownloader.ini进行配置,缺省为:F:/myDownloader 20、功能尚在扩展,请多提意见和建议。 2009年10月 CASHUANGNING
### 回答1: 好的,我可以向你提供一个基本的多线程断点续传下载方法。 首先,你需要创建一个线程类,用于下载文件的指定部分。这个线程类需要记录文件的开始和结束位置,并且在运行时使用这些位置来设置 HTTP 请求的 `Range` 头部。 然后,你可以创建一个主线程来管理多个下载线程。这个主线程需要获取文件的大小,并将文件分成若干个部分来下载。每个部分对应一个下载线程。 最后,你需要创建一个控制类来管理主线程和下载线程。这个控制类需要记录文件下载进度,并提供方法来开始、暂停和继续下载。 下面是一个示例代码,它展示了如何使用 Java 实现多线程断点续传下载方法。这个示例使用Java 内置的 `ExecutorService` 来管理下载线程,并使用了 `CountDownLatch` 来等待所有线程完成。 ```java import java.io.IOException; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MultiThreadDownloader { ### 回答2: 要编写一个多线程断点续传下载方法,可以使用Java多线程机制和输入输出流进行下载和保存文件的操作。 首先,创建一个下载方法,该方法需要接收下载的URL和本地保存文件的路径作为参数。在方法内部可以使用try-catch块来捕获可能的异常。 在下载方法内部,首先通过URL对象打开连接,并设置连接超时时间和请求参数。然后通过HttpURLConnection对象获取下载文件的总大小,并检查本地是否存在已下载的部分文件。 如果已有部分文件存在,就设置连接的Range头参数指定从现有文件的末尾开始下载。如果不存在部分文件,则创建一个新的文件来保存下载内容。这里可以使用RandomAccessFile类来支持随机访问文件。 然后,创建多个线程来进行文件下载。可以根据文件大小和预设的线程数量来确定每个线程负责下载文件范围。每个线程都应该打开一个输入流来读取远程文件的内容,并打开一个输出流将内容写入本地文件。 在下载过程,可以设置一个缓冲区来提高效率。可以使用byte数组作为缓冲区,在循环不断读取输入流的内容并写入输出流。 每个线程完成下载后,应该将已下载的字节数保存到一个全局变量。所有线程下载完成后,可以关闭输入流和输出流,并检查下载是否成功。 如果下载成功,可以将下载进度保存到本地文件或数据库,以便在需要时进行断点续传;如果下载未完成或失败,应将下载的临时文件删除,以防止出现错误的文件。 最后,在应用程序调用这个下载方法,传入下载的URL和保存文件的路径即可开始下载,并可以设置断点续传的功能。 这就是一个使用Java多线程实现断点续传下载方法的基本思路。根据实际需求,还可以添加进度条显示、下载速度计算等功能来提升用户体验。 ### 回答3: 编写Java多线程断点续传下载方法,主要需要实现以下几个步骤: 1. 创建一个类来表示下载任务,其包含下载链接、保存路径、文件名等相关信息,以及记录已经下载的字节数等状态信息。 2. 在下载方法,首先判断之前是否有未下载完的文件,如果有,则将已下载的字节数设置为已完成的字节数。 3. 设置多线程下载的线程数,根据文件大小计算每个线程需要下载的字节数。 4. 创建多个线程,每个线程的下载范围(起始和结束字节位置)根据已下载的字节数和计算得出。 5. 在每个线程,根据指定的范围发送HTTP请求获取文件字节流,然后将字节流写入文件指定的位置,并累加已下载的字节数。 6. 当所有线程都下载完成后,将下载任务标志为已完成。 7. 如果下载过程出现异常或者手动下载,则保存已下载的字节数,并将下载任务标志为未完成。 8. 如果下载断后重新进行下载任务,则从保存的已下载字节数开始,继续进行下载。 9. 下载完成后,关闭所有的线程,释放资源。 通过上述步骤,我们可以实现一个多线程断点续传下载方法,并保证在断或异常情况下能够从上次断的位置继续下载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值