一、 原理:
1 不是说多线程开的越多越快。(手机迅雷 建议3-4个)
2 还受服务器带宽的影响。
3 可以理解为更多的cpu资源给了你(司马光砸缸多砸了几个口)
二 、 分析 把服务器的文件资源等分 客户端 分别下载每一小快 一起进行
1 获得服务器文件大小
2 在客户端创建大小和服务器端一样的文件(提前申请好空间)
2.1 每个线程下载的开始结束位置 记录
3 开多个线程下载文件
4 知道每个线程什么时候下载完毕
三、补充:随机访问文件(RandomAccessFile类)
此类的事例支持对随机访问文件的读取写入
1、构造函数:
RandomAccessFile(File file,String mode)
mode可以为:r rw rws(包含元数据) rwd
RandomAccessFile(String name,String mode)
2、 一些方法:
read()
write()
setLength() 设置此文件的长度
seek(long pos) 设置指针偏移量 (达到每个线程从自己的位置开始)
Demo:
package com.example.administrator.httpclientdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class MainActivity extends AppCompatActivity {
// private static String PATH = "http://xiazai.sogou.com/comm/redir?softdown=1&u=0Gd8piB609380vCOL7GwJe7o9WVvkHDRKoqPuf-gGiXUWLXBAm9x94tIfhLGrwKWYNK-LbFKNWlpNfJyk0ESHL8iE21YxdYX&pcid=-3080605666447722537&filename=QQ_Setup.exe&w=1907&stamp=20171204";//要下载文件的路径
private static String PATH="http://192.168.56.1/Demo/girls.jpg";
private static int ThreadCount = 3;//假设开启三个线程
private Button btnMutilDownload;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUI();//初始化ui
}
private void initUI() {
btnMutilDownload = (Button) findViewById(R.id.mutil_down_load);
// 点击事件处理
btnMutilDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 下载逻辑
httpRequest();
}
});
}
private void httpRequest() {
//开启线程处理耗时 逻辑
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(PATH);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int code = connection.getResponseCode();
if (code == 200) {
// 请求成功 进行多线程下载的操作(四个步骤)
// 1 获取服务器返回文件的大小
int length = connection.getContentLength();
Log.d("TAG", "文件大小(字节) :" + length);
// 2 在客户端创建大小和服务器端一样的文件(提前申请好空间)
RandomAccessFile rafAccessFile = new RandomAccessFile(getCacheDir()+"gril.jpg", "rw");
rafAccessFile.setLength(length);
//计算每个线程下载的大小
int blockSize = length / ThreadCount;
for (int i = 0; i < ThreadCount; i++) {
int startIndex = i * blockSize;
int endIndex = (i + 1) * blockSize - 1;
// 特殊情况 最后一个线程
if (i == ThreadCount - 1) {
endIndex = length - 1;
}
// 3 开启线程去服务器下载文件 循环三次 三个线程
new DownLoadThread(startIndex,endIndex,i).start();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
// 定义线程去服务器现在文件
class DownLoadThread extends Thread {
// 通过构造方法吧每个线程 下载的开始结束位置传进来
private int startIndex;
private int endIndex;
private int ThreadId;
public DownLoadThread(int startIndex, int endIndex, int ThreadId) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.ThreadId = ThreadId;
}
@Override
public void run() {
//去服务器下载文件的逻辑
HttpURLConnection connection = null;
try {
URL url = new URL(PATH);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("GET");
// 4 设置一个请求头Range(告诉服务器每个线程下载的开始结束位置)固定写法
connection.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);
//设置分段下载的头信息。 Range:做分段数据请求用的
int code = connection.getResponseCode();
// 5 获得状态码
if (code == 206) {
RandomAccessFile raf = new RandomAccessFile(getCacheDir()+"gril.jpg", "rw");
raf.seek(startIndex);
InputStream in = connection.getInputStream();
//把数据写到文件中
int len=-1;
byte []buff = new byte[1024];
while((len=in.read())!=-1){
raf.write(buff,0,len);
}
raf.close();
Log.d("Tag", "下载完毕"+ThreadId);
}
} catch (Exception e) {
e.prin tStackTrace();
}
}
}
}
网友评论