安卓中多线程断点续传文件下载核心代码总结

本文介绍了一种基于Android平台的多线程断点续传技术实现方案。通过对文件进行分段,每个线程负责下载特定区间的文件内容,利用临时文件记录已下载部分,实现断点续传功能。文章详细解释了如何分配各线程任务、处理断点续传逻辑以及最终文件合成的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学习了Android多线程断点续传,这里做个小小的总结,我觉得下载的几处关键:创建临时文件并计算每个线程需要下载的部分size,每个线程需要下载的开始和结束startIndex和endIndexe,使用获取的流的长度除以size就得到了每个线程需要下载的部分大小,但是如果除不尽的都留给最后一个线程来下载,

然后就是保证断点续传的机制,使用的是临时文件来存放每个线程下载的进度,每次开始都会判断一下临时文件是否存在,以及记录的对应的线程下载记录,根据记录开始本次下载,判断每个线程是否下载完毕,若果都下载完毕则通过循环删除临时文件,

具体下载过程,再次获取连接,根据206的状态码获取读取流,然后就是Java中的io读写的过程了,需要用到的RandomAccessFile来实现临时文件的创建和写入,简单说是因为每个线程请求的部分不同,因而写入的时候也不是从零开始写的,而RandomAccessFile的seek方法,支持写入时的定位,也就是 在指定位置写入文件,然后几个部分拼凑起来就是完成的要下载的文件了。

此外还有需要注意的细节,比如请求网络的代码要放在子线程中来实现,但是更新进度条棒的操作需要在主线程中来实现,因为主线程中不可以做耗时的操作,另外,将线程当前的下载进度写入到文件的过程需要放在随机写入流的后面来执行,避免意外的中断导致文件中产生了记录而随机访问流还没有来得及写入的情况!

public class Demo {
	static String path = "http://192.168.1.106:8080/OneKey.exe";
	static int THREAD_COUNT = 3;
	static int count = 0;
	/**
	 * 分析:多线程下载的思路
	 * 1.首先要有一个访问的地址,根据该地址建立一次连接,
	 * 2.通过建立的连接返回的状态行来设置本地临时文件的大小,并且根据path获取文件名
	 * 3.多个线程下载,所以要计算出每个线程需要下载的数据大小,计算每个线程的开始和结束位置,以确定每个线程请求下载的范围。
	 * 4.打开本地临时文件流,设置每个线程写入本地临时文件的开始位置,和每个线程的请求范围
	 * 5.获取流,读取,写入到临时文件
	 */
	public static void main(String[] args){
		
		
		try {
			URL url = new URL(path);
			HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
			openConnection.setReadTimeout(8*1000);
			openConnection.setConnectTimeout(8*1000);
			openConnection.setRequestMethod("GET");
			if(openConnection.getResponseCode() == 200){
				int Length = openConnection.getContentLength();
				RandomAccessFile raf = new RandomAccessFile(new File(getFileNameFromPath(path)), "rwd");
				raf.setLength(Length);
				raf.close();
				//计算每个线程需要下载的部分
				int size = Length/THREAD_COUNT;
				for(int i=0;i<THREAD_COUNT;i++){
					int startIndex = i*size;
					int endIndex = (i+1)*size-1;
					if(i == THREAD_COUNT-1){
						endIndex = Length-1;
					}
					System.out.println("线程"+i+"的下载区间为:"+startIndex+"-"+endIndex);
					new DownLoadThread(startIndex,endIndex,i).start();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	static String getFileNameFromPath(String path) {
		int index = path.lastIndexOf("/");
		return path.substring(index+1);
	}
}

class DownLoadThread extends Thread{
	
	private int startIndex;
	private int endIndex;
	private int ThreadID;

	/**
	 * 考虑加上断点续传问题,思路就是定义一个变量记录线程当前下载的总量,
	 * 如果线程中断,下次继续下载的时候,就将记录的这个值传给线程,让线程从这个值
	 * 开始下载,一般保存到临时文件中,下载完毕,文件删除即可。
	 * @param startIndex
	 * @param endIndex
	 * @param ThreadID
	 */
	public DownLoadThread(int startIndex, int endIndex, int ThreadID) {
		super();
		this.startIndex=startIndex;
		this.endIndex=endIndex;
		this.ThreadID=ThreadID;
	}
		
		public void run(){
			try {
				int progress = 0;
				File file = new File(ThreadID+".txt");
				if(file.exists()){
					FileInputStream in = new FileInputStream(file);
					BufferedReader br = new BufferedReader(new InputStreamReader(in));
					progress = Integer.parseInt(br.readLine());
					startIndex +=progress;
					in.close();
					}
				URL url = new URL(Demo.path);
				HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
				openConnection.setReadTimeout(8*1000);
				openConnection.setConnectTimeout(8*1000);
				openConnection.setRequestMethod("GET");
				//设置每个线程需要下载的部分区间
				openConnection.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);
				if(openConnection.getResponseCode() == 206){
					RandomAccessFile raf = new RandomAccessFile(new File(Demo.getFileNameFromPath(Demo.path)), "rwd");
					raf.seek(startIndex);
					InputStream inputStream = openConnection.getInputStream();
					byte[] b = new byte[1024];
					int len = 0;
					int total = progress;
					while((len = inputStream.read(b))!=-1){
						raf.write(b, 0, len);
						total +=len;
						System.out.println("线程"+ThreadID+"的下载总数为:"+total);
						//这里就需要生成一个记录文件了
						RandomAccessFile rafFile = new RandomAccessFile(file, "rwd");
						rafFile.write((total+"").getBytes());
						rafFile.close();
					}
					System.out.println("线程"+ThreadID+"下载完毕******************************");
					raf.close();
					
					Demo.count++;
					synchronized (Demo.path) {
						if(Demo.count == 3){
							for(int i=0;i<Demo.count;i++){
								File f = new File(i+".txt");
								f.delete();
							}
						}
					}
					
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值