断点续传下载速度限制
今天boss提出部分文件需要后台低速下载的要求,主要为了不影响正常使用,工作三四年还真没接触过限速下载这个功能,因此特地去看了一下资料。 和我自己所料不差,大部分限速都是在read之后通过Thread的sleep方法实现,即控制下载的吞吐量,这样可以达到一秒内下载量的限制,但是read的过程却无法做限制,这是一大遗憾,作者暂时还在资料搜寻中,先把这种简单的限速放给大家。
public class SpeedLimitUtil {
private long prevTime = 0;
private long bytePrev = 0;//前一次记录的文件大小
private long byteSum = 0;//总共读取的文件大小
private int fileLength = 0;
private int limit = 0;
public SpeedLimitUtil(long startSize,int fileLength,int limit){
this.prevTime = System.currentTimeMillis();
this.bytePrev = startSize;
this.byteSum = startSize;
this.fileLength = fileLength;
this.limit = limit;
}
/**
* 检查当前buffer下载的速度是否过快,过快则返回需要delay的时间
* @param len
* @return
*/
public long checkSpeed(int len){
byteSum += len;
//当前时间
long currentTime = System.currentTimeMillis();
int speed = 0;
if (currentTime - prevTime > 0) {
//避免两次读数太近,导致分母为0
speed = (int) ((byteSum - bytePrev) / (currentTime - prevTime));
}
// LogUtil.e("HongLi","len:" + len + ";speed:" + speed + ";b length:" + b.length);
if (limit > 0 && (fileLength - byteSum) > limit) {//设置了限速,且不是最后一次read
if (speed > limit) {//如果本身速度小于limit就不需要限速
//计算出需要等待多久才能达到限速要求:
int sleepTime = (int) ((byteSum - bytePrev) / limit + prevTime - currentTime);
// LogUtil.e("HongLi","限速:" + "sleep " + sleepTime + "ms;byteRead:" + + len + ";speed:" + speed);
return sleepTime > 0 ? sleepTime : 0;
}
}
return 0;
}
/**
* 检查并执行限速
* @param len
* @throws InterruptedException
*/
public void limitSpeed(int len) throws InterruptedException{
long sleepTime = checkSpeed(len);
if(sleepTime > 0){
Thread.sleep(sleepTime);
}
}
}
SpeedLimitUtil用于限速,开始read循环之前创建实例,每次read执行一次limitSpeed方法,判断是否需要delay,delay多少ms。
/**
* 断点续传下载文件
*
* @param fileUrl
* @param localFilePath
* @return
*/
public static boolean downloadFile(String fileUrl, String localFilePath) {
if (TextUtils.isEmpty(fileUrl) || TextUtils.isEmpty(localFilePath)) {
return false;
}
File file = new File(localFilePath);
long size = 0;
if (file.exists()) {
size = file.length();
}
URL url;
boolean downloadSuccess = false;
RandomAccessFile out = null;
HttpURLConnection con = null;
int fileLength = 0;
try {
url = new URL(fileUrl);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(4000);
con.setReadTimeout(10000);
// 设置下载区间
con.setRequestProperty("range", "bytes=" + size + "-");
fileLength = con.getContentLength();
con.connect();
int code = con.getResponseCode();// 只要断点下载,返回的已经不是200,206
//LogUtil.e("HongLi","code:" + code);
if (code == 206) {
InputStream in = con.getInputStream();
// int serverSize = con.getContentLength();
// 必须要使用
out = new RandomAccessFile(file, "rw");
out.seek(size);
byte[] b = new byte[2048];
int len = -1;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
out.close();
downloadSuccess = true;
}else{
downloadSuccess = downloadFileNormal(fileUrl, localFilePath);
}
con.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
downloadSuccess = downloadFileNormal(fileUrl, localFilePath);
} catch (IOException e) {
e.printStackTrace();
downloadSuccess = downloadFileNormal(fileUrl, localFilePath);
} catch (Exception e) {
e.printStackTrace();
downloadSuccess = downloadFileNormal(fileUrl, localFilePath);
} finally {
try {
if (null != out) {
out.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
if (null != con) {
con.disconnect();
}
if (!downloadSuccess && file.exists()) {
file.delete();
}
if(downloadSuccess && !checkDownloadFile(fileLength,file,fileUrl)){
file.delete();
downloadSuccess = downloadFile(fileUrl,localFilePath);
}
}
return downloadSuccess;
}
以上便是断点续传+限速的代码了,断点续传简单描述一下,其实要实现断点续传真的很简单,先看本地是否有下载到一半的文件,如果有则读取此文件的大小,HttpURLConnection请求之前把文件大小给服务器,服务器会从此大小之后返回数据,注意断点续传的responseCode为206. 代码中一下错误处理都很简单,虽然我没有贴代码,但是明眼人一眼就可以看出来了。 下一章我来把静默下载的部分代码贴一下。
Comments
comments powered by zero