最近看了下多线程下载文件,下载总结一下。
原理:
1.首先访问服务器端,获取到需要下载文件的总大小,并在本地创建同样大小的空白文件;这一步很简单,用你熟悉的任何一种网络访问方法,访问服务器都可以,请求成功后获取内容长度,之后利用RandomAccessFile这个类,创建空白文件,把内容长度设置为文件大小。
2.等分任务,计算出每个线程的开始下载位置以及结束下载位置;根据步骤1中获取到的文件长度,除上想要开启的线程总数,求得的整数为每个线程的下载任务大小blockSize,开始下载位置=i*blockSize(i从0开始),停止下载位置=(i+1)*blockSize-1.
3.开启多个线程,为每个线程设置开始下载的位置以及结束下载位置;这一步就开始请求服务器进行真正的文件下载了,需要注意的就是要设置网络请求时的开始位置和停止位置setRequestProperty("Range", "bytes="+startIndext+"-"+endIndext);,responsecode不是200而是206,之后还是利用RandomAccessFile类的seek方法设置文件写入的位置,write方法进行文件的写入。
代码:
package com.example.multhread;
import android.app.Activity;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Created by pactera on 2017/2/4.
*/
public class DownloadManager {
private static final String path = "http://10.5.92.12:8080/loginProject/gg.exe";
private static final String TAG = "DownloadManager";
private static final int ThreadSize = 3;
private Activity activity;
private List<MyThread> threads;
public DownloadManager(Activity activity) {
this.activity = activity;
threads = new ArrayList<MyThread>();
}
public void StartDownload () {
//1.在Android客户端首先创建一个和需要下载的文件相同大小的空白文件
long fileSize = getFileSize();
//2.开启3个线程去下载对应文件
if (fileSize > 0) {
startMutileThread(fileSize);
//3.如果所有线程都下载完毕,服务器的资源就下载完毕了
ifDownLoadSuccess();
} else {
ToastOnScreen("服务器访问异常,请稍后再试");
}
}
private long getFileSize() {
try {
URL url = new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(5000);
int code = con.getResponseCode();
if (code == 200) {
long size = con.getContentLength();//获取文件长度
Log.d(TAG,"文件大小为:"+size);
File f = new File(Environment.getExternalStorageDirectory(),"gg.exe");
RandomAccessFile file = new RandomAccessFile(f,"rwd");//在本地创建文件
file.setLength(size);//将要下载的文件长度,赋给本地文件
file.close();
return size;
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
private void startMutileThread(long fileSize) {
long size = fileSize/ThreadSize;//获取每个线程需要下载文件的长度
for (int i=0; i<ThreadSize; i++) {
long startIndex = i*size;//计算每个线程开始下载文件的位置
long endIndex = (i+1)*size-1;//停止下载文件的位置
if (i==ThreadSize-1) {//如果是最后一个线程,则直接下载完剩余的文件
endIndex = fileSize-1;
}
MyThread thread = new MyThread(startIndex,endIndex);//开启线程
threads.add(thread);
thread.start();
}
}
private class MyThread extends Thread {
private long startIndex;
private long endIndex;
public MyThread(long startIndex, long endIndex) {
this.startIndex = startIndex;//开始下载的位置
this.endIndex = endIndex;//停止下载的位置
Log.d(TAG,startIndex+"-"+endIndex+"部分文件开始下载!");
}
@Override
public void run() {
super.run();
try {
URL url = new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);//设置请求头,设置开始下载位置和停止位置
con.setConnectTimeout(5000);
int code = con.getResponseCode();
if (code == 206) {//分段下载的返回码是206不是200
InputStream is = con.getInputStream();
File f = new File(Environment.getExternalStorageDirectory(),"gg.exe");
RandomAccessFile file = new RandomAccessFile(f,"rw");//在本地创建文件
file.seek(startIndex);
int len;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
file.write(buffer,0,len);
}
is.close();
file.close();
Log.d(TAG,startIndex+"-"+endIndex+"部分文件下载完毕!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void ifDownLoadSuccess() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
int closeThread = 0;
for (MyThread t:threads) {
if (!t.isAlive()) {
closeThread++;
}
}
if (closeThread == ThreadSize) {
ToastOnScreen("下载完成");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void ToastOnScreen(final String s) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(activity, s, Toast.LENGTH_LONG).show();
}
});
}
}