多线程下载---断点续传

<span style="font-size:18px;">package com.melody.download;

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;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {
	
	static String path = "http://192.168.119.14/ep.exe";
	static int threadCount = 3;     //定义线程数量
	static int finishedThread= 0;    //定义完成进度的线程
	private static ProgressBar pb;
	private static TextView tv;
	static int downLoadProgress = 0;    //所有线程下载总进度
	
	//handle刷新文字进度条
	static Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			//获取当前进度 *100 / 最大进度 + "%"
			tv.setText((long)pb.getProgress() *100 / pb.getMax() + "%");
		};
	};
	
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//拿到进度条控件
		pb = (ProgressBar) findViewById(R.id.pd);
		tv = (TextView) findViewById(R.id.tv);
	}
	
	/**
	 * 点击按钮开始下载
	 * 
	 */
	public void click (View v){
		
		Thread t = new Thread() {
			@Override
			public void run() {
				//发送http请求,拿到目标文件长度
				try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setReadTimeout(8000);
					conn.setConnectTimeout(8000);
					
					if(conn.getResponseCode() == 200){
						//获取长度
						int length = conn.getContentLength();
						
						//创建临时文件   先占用硬盘空间  
						// File(路径,文件名)    路径不写默认存到项目的根目录
		 				File file = new File(Environment.getExternalStorageDirectory(),getNameFrompath(path));
		 				
		 				//随机存储,创建临时文件  
		 				/**
		 				 * mode :
		 				 *  r:只读
		 				 *  rw:读写,文件不存在,则创建
		 				 *  rws:读写,对文件内容或者元数据的每个更新都同步写入到底层存储设备
		 				 *  rwd:读写,对文件内容的每个更新都同步写入到底层存储设备
		 				 */
						RandomAccessFile raf = new RandomAccessFile(file, "rwd");
						//设置临时文件大小与目标文件一直
						raf.setLength(length);
						raf.close();
						
						//设置进度条的最大值长度
						pb.setMax(length);
						
						//计算每个线程区间
						int size = length / threadCount;
						//计算每个线程开始的位置和结束的位置
						for(int id = 0; id < threadCount; id++){
							int startIndex = id * size;   //开始位置 
							int endIndex = (id+1)*size-1;    //结束位置
							if(id == threadCount -1){			//最后一个线程结束的位置
								endIndex = length -1;
							}
							System.out.println("线程" + id +"下载的区间" + startIndex + "~" + endIndex);
						
							new DownLoad(id, startIndex, endIndex).start();
						}
						
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		t.start();
	}
	
	// 截取字段获取文件名
		public static String getNameFrompath(String path){
			//搜索最后一个斜杠
			int index = path.lastIndexOf("/");
			// 斜杠前后开始截取
			return path.substring(index + 1);
		}
		
		//开启下载线程
		public static class DownLoad extends Thread{
			
			int threadId;		     //线程ID
			int startIndex;		//开始区间
			int endIndex;		//结束区间
			
			public DownLoad(int threadId, int startIndex, int endIndex) {
				super();
				this.threadId = threadId;
				this.startIndex = startIndex;
				this.endIndex = endIndex;
			}
			
			public void run() {
				
				try {
					//创建一个文本临时文件,保存下载进度
					File fileProgress = new File(Environment.getExternalStorageDirectory(),threadId+".txt");
					int lastProgress = 0;
					if(fileProgress.exists()){   //判断临时文件是否存在
						//读取进进度临时文件中的内容  创建一个输入流
						FileInputStream fis = new FileInputStream(fileProgress);
						//转为字符流
						BufferedReader br = new BufferedReader(new InputStreamReader(fis));
						//获取读取进度       读取的是上一次的读取进度
						lastProgress = Integer.parseInt(br.readLine());
						//改变下载的开始位置,上一次下载过,这次就不再请求
						startIndex += lastProgress;
						fis.close();
						
						//把上一次下载的进度加到进入条进度中
						downLoadProgress += lastProgress;
						pb.setProgress(downLoadProgress);
						
						//发送消息让文本进度条改变
						handler.sendEmptyMessage(1);
					}
					
					//发送http请求,请求要下载的数据
					URL url = new URL(path);
					HttpURLConnection conn =(HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setReadTimeout(8000);
					conn.setReadTimeout(8000);
					
					//设置请求数据区间    从startIndex到endIndex之间
					conn.setRequestProperty("Range", "bytes=" + startIndex +"-" + endIndex);
					//请求部分数据成功的响应吗是206
					if(conn.getResponseCode() == 206){
						InputStream is = conn.getInputStream();
						//开始读取数据
						byte[] b = new byte[1024];
						int len = 0;
						//当前线程下载的总进度
						int total = lastProgress;    
						//读取临时文件里的数据
						File file = new File(Environment.getExternalStorageDirectory(),getNameFrompath(path));
						RandomAccessFile raf = new RandomAccessFile(file, "rwd");
						//设置写入文件的开始位置
						raf.seek(startIndex);
						//没读取1K就把这1K写到输出流里面
						while((len = is.read(b)) != -1){
							raf.write(b,0,len);
							total +=len;
							System.out.println("线程" + threadId +"下载了:"+total);
						
							//把读取的文件随机存储到临时文件中
							RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
							//每次下载1024个字节,就马上把1024写入文本临时文件
							rafProgress.write((total + "").getBytes());
							rafProgress.close();
							
							//把每次下载的len长度字节马上把len加到下载进去中,让进度条反映出len长度的进度
							downLoadProgress += len;
							pb.setProgress(downLoadProgress);

							//发送消息让文本进度条改变
							handler.sendEmptyMessage(1);
						}
						
						raf.close();
						System.out.println("线程" + threadId +"下载完毕"+"-------------------------");
					
						//下载完毕后删除临时文件
						//判断3调线程全部下载完毕采取删除进度临时文件
						finishedThread++;    //每条线程完毕后都++
						//同步语句块
						synchronized (path) {
							if(finishedThread ==threadCount){   //如果线条=threadCount表示成立,都下载完
								for (int i = 0; i < threadCount; i++) {  //用for循环删除所有临时文件
									File f = new File(Environment.getExternalStorageDirectory(),i+".txt"); 
									f.delete();
								}
								finishedThread = 0;
							}
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
		}
		
		
}
</span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">///布局文件代码</span>
<pre name="code" class="java"><span style="font-size:18px;"><Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:text="点击下载 "/>
    
    <ProgressBar
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:id="@+id/pd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         />
    <TextView 
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0%"
        android:layout_gravity="right"/></span>


 

添加权限 xml 文件//

<span style="font-size:18px;"><uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/></span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值