断点多线程下载

来源:互联网 发布:java连接符 编辑:程序博客网 时间:2024/06/04 19:37
1.在manifest文件中注册权限:网络权限<uses-permission android:name="android.permission.INTERNET"/>sd卡写入权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>2.可以直接在子线程中更新ProgressBar界面package com.example.mutidownload02;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.text.TextUtils;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener {protected static final int DOWN_LAOD_ERROR = 1;protected static final int SERVER_ERROR = 2;public static final int DOEN_LOAD_FINSIH = 3;private static final int UDATE_TEXT = 4;private Button download;private ProgressBar pb;private EditText et_path;private static int threadCount = 4;private static int runningThread = 4;private int currentProgress = 0;private TextView tv_process;private Handler handler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case DOWN_LAOD_ERROR:Toast.makeText(MainActivity.this, "下载错误", 0).show();break;case SERVER_ERROR:Toast.makeText(MainActivity.this, "服务器错误", 0).show();break;case DOEN_LOAD_FINSIH:Toast.makeText(MainActivity.this, "下载完成", 0).show();break;case UDATE_TEXT:// 设置进度条的总进度,pb.getProgress()为取得当前进度,pb.getMax()为取得进度条大小tv_process.setText("当前进度:" + pb.getProgress() * 100/ pb.getMax() + "%");break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);pb = (ProgressBar) findViewById(R.id.progressBar);download = (Button) findViewById(R.id.download);download.setOnClickListener(this);tv_process = (TextView) findViewById(R.id.tv_process);}@Overridepublic void onClick(View view) {final String path = et_path.getText().toString().trim();if (TextUtils.isEmpty(path)) {Toast.makeText(this, "路径不能为空", 0).show();return;}new Thread() {public void run() {try {// String path = "http://192.168.1.102:8080/360.exe";URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);int code = conn.getResponseCode();if (code == 200) {// 服务器返回数据的的长度,就是文件的长度int length = conn.getContentLength();pb.setMax(length);// 在客户端本地新建一个大小和服务器文件一样大小的临时文件RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe", "rwd");// 指定这个临时文件的长度raf.setLength(length);int blockSize = length / threadCount;for (int threadId = 1; threadId <= threadCount; threadId++) {int startIndex = (threadId - 1) * blockSize;int endIndex = threadId * blockSize - 1;// 最后一个线程的长度的位置指定为他的总长度位置if (threadId == threadCount) {endIndex = length;}System.out.println("线程:" + threadId + " 下载:--->"+ startIndex + "--->" + endIndex);new DownloadThread(threadId, startIndex, endIndex,path).start();}} else {Message msg = new Message();msg.what = SERVER_ERROR;handler.sendMessage(msg);}} catch (Exception e) {Message msg = new Message();msg.what = DOWN_LAOD_ERROR;handler.sendMessage(msg);e.printStackTrace();}}}.start();}public class DownloadThread extends Thread {private int threadId;private int startIndex;private int endIndex;private String path;public DownloadThread(int threadId, int startIndex, int endIndex,String path) {super();this.threadId = threadId;this.startIndex = startIndex;this.endIndex = endIndex;this.path = path;}public void run() {try {// 检查是不是存在记录下载长度的文件,如果存在读取这个文件的数据File tempFile = new File("/sdcard/" + threadId + ".txt");if (tempFile.exists() && tempFile.length() > 0) {FileInputStream fis = new FileInputStream(tempFile);byte temp[] = new byte[1024];int length = fis.read(temp);String downloadLen = new String(temp, 0, length);int downloadlenInt = Integer.parseInt(downloadLen);// 下载的开始位置currentProgress += downloadlenInt;startIndex = downloadlenInt;fis.close();}URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");// 请求服务器下载部分文件的位置conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);System.out.println("线程真实下载位置: " + threadId + " :" + startIndex+ "---->" + endIndex);conn.setConnectTimeout(5000);// 从服务器返回全部资源返回码为200,返回部分资源返回码为206int code = conn.getResponseCode();System.out.println(code);if (code == 206) {// 随机文件写入流RandomAccessFile raf = new RandomAccessFile("/sdcard/steup.exe", "rwd");// 随机文件从哪个位置开始写raf.seek(startIndex);InputStream is = conn.getInputStream();int len = 0;byte buffer[] = new byte[1024];int total = 0;while ((len = is.read(buffer)) != -1) {raf.write(buffer, 0, len);total += len;// 更新进度条的位置synchronized (MainActivity.this) {currentProgress += len;// 设置进度条的位置pb.setProgress(currentProgress);Message msg = Message.obtain();msg.what = UDATE_TEXT;handler.sendMessage(msg);}}FileOutputStream fos = new FileOutputStream(new File("/sdcard/" + threadId + ".txt"));fos.write((total + startIndex + "").getBytes());fos.close();is.close();raf.close();System.out.println("线程:" + threadId + "下载完成");} else {System.out.println("线程:" + threadId + "下载出错..");}} catch (Exception e) {e.printStackTrace();} finally {threadFinish();}}private synchronized void threadFinish() {runningThread--;if (runningThread == 0) {for (int i = 1; i <= 4; i++) {File file = new File("/sdcard/" + i + ".txt");file.delete();}System.out.println("文件下载完成,删除所有文件记录");Message msg = new Message();msg.what = DOEN_LOAD_FINSIH;handler.sendMessage(msg);}}}}全部代码:package com.example.mutidownload02;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.text.TextUtils;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener {protected static final int DOWN_LAOD_ERROR = 1;protected static final int SERVER_ERROR = 2;public static final int DOEN_LOAD_FINSIH = 3;private static final int UDATE_TEXT = 4;private Button download;private ProgressBar pb;private EditText et_path;private static int threadCount = 4;private static int runningThread = 4;private int currentProgress = 0;private TextView tv_process;private Handler handler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case DOWN_LAOD_ERROR:Toast.makeText(MainActivity.this, "下载错误", 0).show();break;case SERVER_ERROR:Toast.makeText(MainActivity.this, "服务器错误", 0).show();break;case DOEN_LOAD_FINSIH:Toast.makeText(MainActivity.this, "下载完成", 0).show();break;case UDATE_TEXT:tv_process.setText("当前进度:" + pb.getProgress() * 100/ pb.getMax() + "%");break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);pb = (ProgressBar) findViewById(R.id.progressBar);download = (Button) findViewById(R.id.download);download.setOnClickListener(this);tv_process = (TextView) findViewById(R.id.tv_process);}@Overridepublic void onClick(View view) {final String path = et_path.getText().toString().trim();if (TextUtils.isEmpty(path)) {Toast.makeText(this, "路径不能为空", 0).show();return;}new Thread() {public void run() {try {// String path = "http://192.168.1.102:8080/360.exe";URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);int code = conn.getResponseCode();if (code == 200) {int length = conn.getContentLength();pb.setMax(length);RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe", "rwd");raf.setLength(length);int blockSize = length / threadCount;for (int threadId = 1; threadId <= threadCount; threadId++) {int startIndex = (threadId - 1) * blockSize;int endIndex = threadId * blockSize - 1;if (threadId == threadCount) {endIndex = length;}System.out.println("线程:" + threadId + " 下载:--->"+ startIndex + "--->" + endIndex);new DownloadThread(threadId, startIndex, endIndex,path).start();}} else {Message msg = new Message();msg.what = SERVER_ERROR;handler.sendMessage(msg);}} catch (Exception e) {Message msg = new Message();msg.what = DOWN_LAOD_ERROR;handler.sendMessage(msg);e.printStackTrace();}}}.start();}public class DownloadThread extends Thread {private int threadId;private int startIndex;private int endIndex;private String path;public DownloadThread(int threadId, int startIndex, int endIndex,String path) {super();this.threadId = threadId;this.startIndex = startIndex;this.endIndex = endIndex;this.path = path;}public void run() {try {File tempFile = new File("/sdcard/" + threadId + ".txt");if (tempFile.exists() && tempFile.length() > 0) {FileInputStream fis = new FileInputStream(tempFile);byte temp[] = new byte[1024];int length = fis.read(temp);String downloadLen = new String(temp, 0, length);int downloadlenInt = Integer.parseInt(downloadLen);currentProgress += downloadlenInt;startIndex = downloadlenInt;fis.close();}URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);System.out.println("线程真实下载位置: " + threadId + " :" + startIndex+ "---->" + endIndex);conn.setConnectTimeout(5000);int code = conn.getResponseCode();System.out.println(code);if (code == 206) {RandomAccessFile raf = new RandomAccessFile("/sdcard/steup.exe", "rwd");raf.seek(startIndex);InputStream is = conn.getInputStream();int len = 0;byte buffer[] = new byte[1024];int total = 0;while ((len = is.read(buffer)) != -1) {raf.write(buffer, 0, len);total += len;synchronized (MainActivity.this) {currentProgress += len;pb.setProgress(currentProgress);Message msg = Message.obtain();msg.what = UDATE_TEXT;handler.sendMessage(msg);}}FileOutputStream fos = new FileOutputStream(new File("/sdcard/" + threadId + ".txt"));fos.write((total + startIndex + "").getBytes());fos.close();is.close();raf.close();System.out.println("线程:" + threadId + "下载完成");} else {System.out.println("线程:" + threadId + "下载出错..");}} catch (Exception e) {e.printStackTrace();} finally {threadFinish();}}private synchronized void threadFinish() {runningThread--;if (runningThread == 0) {for (int i = 1; i <= 4; i++) {File file = new File("/sdcard/" + i + ".txt");file.delete();}System.out.println("文件下载完成,删除所有文件记录");Message msg = new Message();msg.what = DOEN_LOAD_FINSIH;handler.sendMessage(msg);}}}} <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context=".MainActivity" >    <EditText        android:id="@+id/et_path"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="请输入路径" >    </EditText>    <ProgressBar        android:id="@+id/progressBar"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/download"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="下载" />    <TextView        android:id="@+id/tv_process"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></LinearLayout>