断点续传和多线程下载(二)

接着第一篇的后面,上次是实现了断点续传的功能,下载的时候能够暂停,程序退出的时候,会记录下载的断点位置,下次再进行下载的时候会接着上次没有下载完成的地方下载。

这一篇在原来断点续传的基础上加入多线程下载的功能。多线程下载,就是把一个下载任务原先是一个子线程完成下载的。现在把这个下载任务分配给多个子线程来下载,已达到占用较多的带宽来下载资源的目的。

1、首先得到下载的文件的大小,然后根据下载的子线程数来分配每个线程负责下载的部分

2、将每个子线程的负责下载的位置,即startPos和endPos都分配好之后,保存到数据库中

3、从容器中把每个线程拿出来,然后创建下载任务,开始下载

4、下载的时候,HttpURLConnection的setRequestProperty()方法注意请求得到的文件长度为该线程之前分配好的文件长度

5、下载中,同断点续传一样,一边下载时,一边将每个线程的下载进度保存到数据库中


部分代码:

	@Override
	protected List<DownloadInfo> doInBackground(String... args) {
		String urlStr = args[0];
		infos = DownloadDao.getInstance(context).getDownloadInfos(urlStr);
		if (infos == null || infos.isEmpty()) {
			try {
				URL url = new URL(args[0]);
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setReadTimeout(5000);
				conn.setRequestMethod("GET");
				fileSize = conn.getContentLength();

			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			int range = fileSize / threadCount;
			for (int i = 0; i < threadCount - 1; i++) {
				DownloadInfo info = new DownloadInfo(fileSize, 0, urlStr, i
						* range, (i + 1) * range - 1, i);
				infos.add(info);
			}
			DownloadInfo info = new DownloadInfo(fileSize, 0, urlStr, fileSize
					- range, fileSize, threadCount - 1);
			infos.add(info);

			DownloadDao.getInstance(context).saveDownloadInfos(infos);

			return infos;
		}
		return infos;
	}

	@Override
	protected void onPostExecute(List<DownloadInfo> infos) {
		super.onPostExecute(infos);
		if (infos == null && infos.isEmpty()) {
			return;
		}
		int progress = getProgress(infos);
		getFileSize(infos);
		callback.setProgress(progress,fileSize);
		DownloadTask task = new DownloadTask(context, handler,fileSize);
		task.STATE = DownloadTask.DOWNLOADING;
		task.download(infos);
	}

DownloadTask:

package com.shulf.downloadtest;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.List;

import android.content.Context;
import android.os.Handler;
import android.os.Message;

/**
 * 下载线程类,得到下载实体中的信息,开启线程进行下载
 * 
 * @author Administrator
 * 
 */
public class DownloadTask{

	private Handler handler;
	
	private Context context;
	
	/*
	 * 下载的文件大小
	 */
	private int fileSize;
	
	/*
	 * 整个文件下载的完成度
	 */
	private int mComplete = 0;
	
	/*
	 * 下载状态
	 */
	public static int DOWNLOADING = 1;
	
	/*
	 * 暂停状态
	 */
	public static int PAUSE = 2;
	
	public static int STATE = DOWNLOADING;// 1表示未下载状态,2表示暂停状态

	public DownloadTask(Context context, Handler handler,int fileSize) {
		this.fileSize = fileSize;
		this.context = context;
		this.handler = handler;
	}
	
	/**
	 * 得到下载的所有下载实体(所有线程)
	 * @param infos
	 */
	public void download(List<DownloadInfo> infos) {
		for (int i = 0; i < infos.size(); i++) {
			DownloadInfo info = infos.get(i);
			new DownloadThread(info).start();
		}
	}
	
	/**
	 * 开启线程正式下载
	 * @author Administrator
	 *
	 */
	private class DownloadThread extends Thread {
		private DownloadInfo info;

		public DownloadThread(DownloadInfo info) {
			this.info = info;
		}

		@Override
		public void run() {
			HttpURLConnection conn = null;
			InputStream in = null;
			RandomAccessFile randomAccessFile = null;
			File saveFile = new File("/mnt/sdcard/", "test.apk");
			int completeSize = info.completeSize;
			try {
				URL url = new URL(info.url);
				conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setRequestMethod("GET");
				/** 设置请求头的属性,从断点处开始到文件的长度 */
				conn.setRequestProperty("Range", "bytes="
						+ (info.startPos + completeSize) + "-" + info.endPos);

				randomAccessFile = new RandomAccessFile(saveFile, "rwd");
				randomAccessFile.seek(info.startPos + completeSize);

				in = conn.getInputStream();
				byte[] buffer = new byte[4096];
				int length = -1;
				while ((length = in.read(buffer)) != -1) {
					randomAccessFile.write(buffer, 0, length);
					completeSize += length;
					DownloadDao.getInstance(context).updateComplete(
							info.threadId, info.url, completeSize);
					Message msg = Message.obtain();
					msg.what = 1;
					msg.arg1 = length;
					msg.arg2 =fileSize;
					handler.sendMessage(msg);
					if (STATE == PAUSE) {
						return;
					}
				}
			} catch (ProtocolException e) {
				e.printStackTrace();
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (in != null) {
						in.close();
					}
					if (randomAccessFile != null) {
						randomAccessFile.close();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		}
	}

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程断点续传下载可以使用Java中的线程池和RandomAccessFile类实现。具体步骤如下: 1. 创建一个线程池,线程数量可以根据需要调整。 ``` ExecutorService executorService = Executors.newFixedThreadPool(threadCount); ``` 2. 获取文件大小和已经下载的字节数,计算出每个线程需要下载的字节数。 ``` URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); long fileSize = connection.getContentLength(); long threadSize = fileSize / threadCount; ``` 3. 创建一个RandomAccessFile对象,指定文件名和读写模式。 ``` RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw"); ``` 4. 为每个线程创建一个DownloadThread对象,指定线程编号、起始位置和结束位置。 ``` for (int i = 0; i < threadCount; i++) { long start = i * threadSize; long end = (i == threadCount - 1) ? fileSize - 1 : start + threadSize - 1; DownloadThread thread = new DownloadThread(fileUrl, randomAccessFile, start, end); executorService.execute(thread); } ``` 5. 在DownloadThread中使用HttpURLConnection下载文件,使用RandomAccessFile写入文件。 ``` URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty("Range", "bytes=" + start + "-" + end); InputStream inputStream = connection.getInputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { randomAccessFile.write(buffer, 0, length); } inputStream.close(); ``` 6. 在程序关闭时,关闭RandomAccessFile和线程池。 ``` randomAccessFile.close(); executorService.shutdown(); ``` 这样就可以实现Java多线程断点续传下载了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值