多线程下载的实现:
1、首先获取文件的长度。
2、设置线程的个数
3、根据长度和线程个数计算每一个线程需要下载的长度。
例如:3个线程下载一个为length=10个字节的文件
int bolckSize=length/3;
则每一部分需要下载的大小为:
线程 1 :int start=0*blockSize int end=1*blockSize-1;
线程 2 :int start=1*blockSize int end=2*blockSize-1;
线程 3 :int start=2*blockSize int end=length-1;//到最后
4、根据RandomAccessFile raf 创建一个同样大小的空文件。
5、设置Http请求的头信息
connection.setRequestProperty("range", "bytes=" + start + "-" + end);
6、根据raf.seek(int length),把下载好的数据写入空文件的指定位置,拼接成完整的文件。
实现:
用Tomcat作为服务器,服务器目录C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT下放置了一个guanguan.apk文件。
主界面就一个Button按钮。
public class MainActivity extends Activity implements View.OnClickListener {
// 要下载文件的路径
private String urlPath = "http://localhost:8080/guanguan.apk";
private String filePath;
// 设置线程的数目。
private int threadCount = 3;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.button) {
Log.d("dd","开始下载");
new Thread(new GetDataFromNet()).start();
}
}
//访问网络的类:
private class GetDataFromNet implements Runnable {
@Override
public void run() {
try {
//请求网络
URL url = new URL(urlPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
// 获取返回值
int code = connection.getResponseCode();
if (code == 200) {
// 获取数据总长度
int length = connection.getContentLength();
Log.d("dd","文件长度"+length);
// 设置下载位置
filePath = "/sdcard" + "/guanguan.apk";
File file = new File(filePath);
Log.d("dd", "下载路径:" + filePath);
// 通过RandomAccessFile创建一个空文件。 rwd 文件权限信息
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
// 设置空文件的大小
accessFile.setLength(length);
accessFile.close();
//每一段的大小
int bolckSize = length / threadCount;
//计算每个线程下载的起始位置。
for(int i = 0; i < threadCount; i++) {
int start = i * bolckSize;
int end = (i + 1) * bolckSize - 1;
//如果是最后一个线程,则结束位置为文件的末尾
if (i == (threadCount - 1)) {
end = length-1;
}
Log.d("dd", "第" + i + "个线程" + "从" + start + "到" + end);
new DownloadFile(urlPath, filePath, start, end).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//文件下载类
public class DownloadFile extends Thread {
private String urlPath;//下载路径
private String fileName;//文件保存路径
private int start;//开始位置
private int end;//结束位置
//构造方法
public DownloadFile(String urlPath, String fileName, int start, int end) {
this.urlPath = urlPath;
this.fileName = fileName;
this.start = start;
this.end = end;
}
@Override
public void run() {
URL url = null;
try {
url = new URL(urlPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
// 设置Http头的信息,即要指明获取的是那一段数据。
connection.setRequestProperty("range", "bytes=" + start + "-" + end);
int code = connection.getResponseCode();
//注意部分下载返回的code值为 206
if (code == 206) {
InputStream is = connection.getInputStream();
File file = new File(fileName);
//创建RandomAccessFile,要与上次已经创建文件名以及权限一致
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
//该方法用来操作建造好的空文件,可以指明从文件的那个位置开始写入 accessFile.seek(start); byte[] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) >0) { accessFile.write(buf, 0, len); } is.close(); accessFile.close(); Log.d("dd", "该线程下载了" + start + "--" + end); } } catch (Exception e) { e.printStackTrace(); } } }
运行结果: