<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>