关键词:
package everphoto.bean;
import android.content.Context;
import android.support.v4.util.ArrayMap;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import everphoto.App;
import solid.download.DownloadTask;
import solid.download.DownloadTaskListener;
import solid.util.PathUtils;
/**
* 管理应用所有下载任务,提供以下功能
* 1.任务状态查询
* 2.任务并发控制
* 3.任务暂停、恢复、断点续传
*/
public class FileDownloadMgr
private static final int MAX_CONCURRENT_DOWNLOAD_TASK_NUM = 5;
private static Context context;
private static FileDownloadMgr instance = new FileDownloadMgr();
public static FileDownloadMgr getInstance(Context c)
if (c != null)
context = c;
return instance;
/**
* 必须和taskList保持一致性
*/
private Map<String, DownloadTask> tasks = new ArrayMap<>();
/**
* 任务队列
*/
private LinkedList<String> taskList = new LinkedList<>();
private int concurrentTaskNum = 0;
private FileDownloadMgr()
public boolean pasue(String url)
DownloadTask task = tasks.get(url);
if (null == task)
return false;
task.onCancelled();
finish(url);
return true;
public DownloadTask getTask(String url)
return tasks.get(url);
public boolean putTask(final String url, final DownloadTaskListener listener)
return putTask(url, PathUtils.PATH_DOWNLOAD, null, listener, false);
public boolean putTask(final String url, String fileName, final DownloadTaskListener listener)
return putTask(url, PathUtils.PATH_DOWNLOAD, fileName, listener, false);
public boolean putTask(final String url, String fileName, final DownloadTaskListener listener, boolean force)
return putTask(url, PathUtils.PATH_DOWNLOAD, fileName, listener, force);
/**
* 生成并执行一个下载任务,支持恢复一个被暂停或异常中断的下载任务。
*
* @param url 下载url
* @param path 保存路径
* @param fileName 保存文件的文件名;如果为空,则使用url.getFile()作为文件名
* @param listener DownloadTaskListener
* @param force 是否无视最大下载并发的限制,强制下载
* @return 是否成功生成任务
*/
public boolean putTask(final String url, String path, String fileName, final DownloadTaskListener listener, boolean force)
try
DownloadTask task = new DownloadTask(context, url, path, fileName, new DownloadTaskListener()
@Override
public void updateProcess(DownloadTask task)
listener.updateProcess(task);
@Override
public void finishDownload(DownloadTask task, File file)
try
listener.finishDownload(task, file);
catch (Exception e)
e.printStackTrace();
finish(url);
@Override
public void preDownload()
listener.preDownload();
@Override
public void errorDownload(int error)
listener.errorDownload(error);
, App.getInstance().provideMediaImageHttpClient());
tasks.put(url, task);
taskList.add(url);
execute(task, force);
return true;
catch (MalformedURLException e)
e.printStackTrace();
catch (FileNotFoundException e)
e.printStackTrace();
return false;
/**
* 提供一键暂停、一键恢复功能
*/
public void showNotification()
/**
* @param task 下载任务
* @param force 强制执行下载,忽略最大并发限制
*/
private synchronized void execute(DownloadTask task, boolean force)
if (concurrentTaskNum >= MAX_CONCURRENT_DOWNLOAD_TASK_NUM && !force)
return;
concurrentTaskNum++;
task.execute();
private synchronized void finish(String url)
taskList.remove(url);
tasks.remove(url);
concurrentTaskNum--;
// 找到队列最前面的未执行任务
Iterator iterator = taskList.iterator();
while (iterator.hasNext())
String taskUrl = (String) iterator.next();
DownloadTask task = tasks.get(taskUrl);
if (task != null && task.getStatus() == DownloadTask.Status.PENDING)
execute(task, false);
package solid.download;
import java.io.File;
public interface DownloadTaskListener
void updateProcess(DownloadTask task);
void finishDownload(DownloadTask task, File file);
void preDownload();
void errorDownload(int error);
package solid.download;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import solid.util.FileUtils;
import solid.util.IOUtils;
import solid.util.L;
public class DownloadTask extends AsyncTask<Void, Integer, Long>
public final static int ERROR_NONE = 0;
public final static int ERROR_SD_NO_MEMORY = 1;
public final static int ERROR_BLOCK_INTERNET = 2;
public final static int ERROR_UNKONW = 3;
public final static int TIME_OUT = 30000;
private final static int BUFFER_SIZE = 1024 * 8;
private URL url;
private File file;
private String urlString;
private Throwable exception;
private DownloadTaskListener listener;
private Context context;
private Call call = null;
private OkHttpClient client;
private long downloadSize;
private long previousFileSize;
private long totalSize;
private int downloadPercent;
private long networkSpeed; // 网速
private long previousTime;
private long totalTime;
private int errStatusCode = ERROR_NONE;
private boolean interrupt = false;
public DownloadTask(Context context, String urlString, String path)
throws MalformedURLException, FileNotFoundException
this(context, urlString, path, null, null, null);
public DownloadTask(Context context, String urlString, String path, String fileName, DownloadTaskListener listener, OkHttpClient client)
throws MalformedURLException, FileNotFoundException
super();
this.context = context;
this.urlString = urlString;
this.url = new URL(urlString);
this.listener = listener;
this.client = client;
if (TextUtils.isEmpty(fileName))
fileName = new File(url.getFile()).getName();
fileName = FileUtils.fixFileName(fileName);
L.v(null, "fileName: " + fileName);
if (!FileUtils.makeSurePath(path))
throw new FileNotFoundException("makeSurePath " + path);
this.file = new File(path, fileName);
public DownloadTaskListener getListener()
return listener;
public File getFile()
return file;
public String getUrlString()
return urlString;
public int getDownloadPercent()
return downloadPercent;
public long getDownloadSize()
return downloadSize + previousFileSize;
public long getTotalSize()
return totalSize;
public long getDownloadSpeed()
return this.networkSpeed;
public long getTotalTime()
return this.totalTime;
@Override
public void onCancelled()
super.onCancelled();
interrupt = true;
public int copy(InputStream input, RandomAccessFile out) throws Exception
byte[] buffer = new byte[BUFFER_SIZE];
BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
L.v(null, "length" + out.length());
out.seek(out.length());
int count = 0, n = 0;
long errorBlockTimePreviousTime = -1, expireTime = 0;
try
while (!interrupt)
n = in.read(buffer, 0, BUFFER_SIZE);
if (n == -1)
break;
out.write(buffer, 0, n);
count += n;
if (!isOnline())
interrupt = true;
errStatusCode = ERROR_BLOCK_INTERNET;
break;
if (networkSpeed == 0)
if (errorBlockTimePreviousTime > 0)
expireTime = System.currentTimeMillis() - errorBlockTimePreviousTime;
if (expireTime > TIME_OUT)
errStatusCode = ERROR_BLOCK_INTERNET;
interrupt = true;
else
errorBlockTimePreviousTime = System.currentTimeMillis();
else
expireTime = 0;
errorBlockTimePreviousTime = -1;
finally
try
out.close();
catch (IOException e)
errStatusCode = ERROR_UNKONW;
Log.e(null, e.getMessage(), e);
try
in.close();
catch (IOException e)
errStatusCode = ERROR_UNKONW;
Log.e(null, e.getMessage(), e);
return count;
@Override
protected void onPreExecute()
previousTime = System.currentTimeMillis();
if (listener != null)
listener.preDownload();
@Override
protected Long doInBackground(Void... params)
try
return download();
catch (Exception e)
if (call != null)
call.cancel();
exception = e;
errStatusCode = ERROR_UNKONW;
return null;
@Override
protected void onProgressUpdate(Integer... progress)
if (progress.length > 1)
totalSize = progress[1];
if (totalSize == -1)
if (listener != null)
listener.errorDownload(ERROR_UNKONW);
else
totalTime = System.currentTimeMillis() - previousTime;
downloadSize = progress[0];
downloadPercent = (int) ((downloadSize + previousFileSize) * 100 / totalSize);
networkSpeed = downloadSize / totalTime;
if (listener != null)
listener.updateProcess(this);
@Override
protected void onPostExecute(Long result)
if (interrupt)
if (errStatusCode != ERROR_NONE)
if (listener != null)
listener.errorDownload(errStatusCode);
return;
if (exception != null)
Log.v(null, "Download failed.", exception);
if (listener != null)
listener.finishDownload(this, file);
private long download() throws Exception
L.v(null, "totalSize: " + totalSize);
if (null == client)
client = new OkHttpClient();
Request request = new Request.Builder().url(urlString).build();
Call call = client.newCall(request);
Response response = call.execute();
totalSize = response.body().contentLength();
if (file.length() > 0 && totalSize > 0 && totalSize > file.length())
// 此处要求服务端支持断点续传
request = request.newBuilder().addHeader("Range", "bytes=" + file.length() + "-").build();
previousFileSize = file.length();
call.cancel();
call = client.newCall(request);
response = call.execute();
L.v(null, "File is not complete, download now.");
L.v(null, "File length:" + file.length() + " totalSize:" + totalSize);
else if (file.exists() && totalSize <= file.length())
L.v(null, "Output file already exists. Skipping download.");
publishProgress((int) totalSize);
return 0l;
long storage = FileUtils.getAvailableStorage();
L.i(null, "storage:" + storage + " totalSize:" + totalSize);
if (totalSize - file.length() > storage)
errStatusCode = ERROR_SD_NO_MEMORY;
interrupt = true;
call.cancel();
return 0l;
RandomAccessFile outputStream;
try
outputStream = new ProgressReportingRandomAccessFile(file, "rw");
catch (FileNotFoundException e)
L.v(null, "OutputStream Error");
throw e;
int bytesCopied = 0;
try
publishProgress(0, (int) totalSize);
InputStream input = null;
input = response.body().byteStream();
// try
//// input = response.getEntity().getContent();
// catch (IOException ex)
// errStatusCode = ERROR_UNKONW;
// call.cancel();
// Log.v(null, "InputStream Error" + ex.getMessage());
// return 0;
//
bytesCopied = copy(input, outputStream);
if ((previousFileSize + bytesCopied) != totalSize && totalSize != -1 && !interrupt)
throw new IOException("Download incomplete: " + bytesCopied + " != " + totalSize);
call.cancel();
call = null;
L.v(null, "Download completed successfully.");
finally
IOUtils.close(outputStream);
return bytesCopied;
private boolean isOnline()
try
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null && ni.isConnectedOrConnecting();
catch (Exception e)
e.printStackTrace();
return false;
private final class ProgressReportingRandomAccessFile extends RandomAccessFile
private int progress = 0;
public ProgressReportingRandomAccessFile(File file, String mode)
throws FileNotFoundException
super(file, mode);
@Override
public void write(byte[] buffer, int offset, int count) throws IOException
super.write(buffer, offset, count);
progress += count;
publishProgress(progress);
断点续传基本原理初了解
...个部分,同时进行多个部分一起的下载,当某个时间点,任务被暂停了,此时下载暂停的位置就是断点了。续传就是当一个未完成的下载任务再次开始时,会从上次的断点继续传送。 使用多线程断点续传下载的时候,将... 查看详情
讲讲断点续传那点儿事(代码片段)
...件是否还需要重头开始下载?Q3:你的app下载大文件时,支持暂停并恢复下载么?即使这两个操作分布在程 查看详情
谷歌浏览器下载软件可以断点续传吗?
...可以,不用设置,自动的。关键问题是你所下载的服务器支持不支持。如果不支持也不行。参考技术A在浏览器不关闭的时候可以暂停,但是关闭以后就不能像迅雷一样接着下载了 参考技术B这个与用什么浏览器没关,关键是看所... 查看详情
java实现文件的断点续传
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。第一步:前端修改由于项目使用的是BJUI前端框架,并... 查看详情
html5大文件断点续传完整思路整理
需求:支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验;内网百兆网络上传速度为12MB/S服务器内存占用低支持文件夹上传,文件夹中的文件数量达到1万个以上,且包含层级结构。支持PC端全... 查看详情
如何让chrome断点续传
chrome也有自己的下载系统,而且速度还不错,只是好像不支持断点续传。你可以在迅雷的链接上面点右键,复制链接地址,然后到迅雷里面去新建一个任务,把地址复制到目标地址上面就可以了参考技术A看了GOOGLE还在研究这个... 查看详情
断点续传
一、重点!重点!重点!1、设置数据任务task(从路径中获取文件的长度,再判断是否下载过,来请求url,设置Range,将Range添加到请求头中)。2、写入文件(存储下载文件,通过路径设置输出流,并打开,将之前文件取出来,重新设置... 查看详情
ftpftp文件上传下载-支持断点续传
Jar包:apache的commons-net包;支持断点续传支持进度监控(有时出不来,搞不清原因)相关知识点编码格式:UTF-8等;文件类型:包括[BINARY_FILE_TYPE(常用)]和[ASCII_FILE_TYPE]两种;数据连接模式:一般使用LocalPassiveMode模式,因为大部分客户端... 查看详情
为啥chrome还不支持断点续传
参考技术Achrome内建下载是支持断点续传的只是有些下载服务器不支持而已 查看详情
afnetworking实现程序重新启动时的断点续传(代码片段)
...#xff0c;但是在进行了一番研究之后,发现AFNetworking虽然支持下载文件的暂停和继续,但是程序重新启动后再次下载无法进行续传。网上有说可以通过AFDownloadRequestOperation这个AFNetworking的扩展库来实现重新启动后的续传,... 查看详情
掀开断点续传那一层面纱(下载篇)
...DNS查找、TCP三次握手、http请求发送、TCP协议数据传输、暂停后的状态、继续下载、TCP三次握手、http请求发送、数据传输、。。。、下载成功发送http响应信息、TCP四次握手断开连接。2、原理知识 2.1、问答问答 问:什么... 查看详情
大文件上传服务器支持超大文件http断点续传实践总结(代码片段)
...s/80490621最近由于笔者所在的研发集团产品需要,需要支持高性能的大文件http上传,并且要求支持http断点续传。这里在简要归纳一下,方便记忆:服务器端由C语言实现,而不是用java、PHP这种解释型语言来实现... 查看详情
超大文件上传和断点续传的组件
...经下载的地方开始继续下载。在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了。一般断点下载时才用到Range和Content-Range实体头。HTTP协议本身不支持断点上传,需要自己实现。 二、Range 用于请求头中,指定... 查看详情
rsync支持断点续传文件
参考:https://my.oschina.net/ccLlinux/blog/1859116基本命令:rsync[OPTION]…SRC(需要备份的原文件)DEST(Push的位置)example:download:rsync-avuser@hostip:/scratch/test/test_sh.sh/Users/username/test/test.sh上传:rsync-av/Users/u 查看详情
支持断点续传的大文件传输协议
...要手段,在数据通信领域一直发挥着举足轻重的作用,不支持断点续传,是Internet上最早也是最广泛使用的应用之一.从1971年A.K.Bhushan提出第一个FTP协议版本(RFC114)到现在,人们对FTP的应用已经历了40余年的时间,同时,许多基... 查看详情
文件下载之断点续传(客户端与服务端的实现)
【转】文件下载之断点续传(客户端与服务端的实现)【转】文件下载之断点续传(客户端与服务端的实现)前面讲了文件的上传,今天来聊聊文件的下载。老规矩,还是从最简单粗暴的开始。那么多简单算简单?多粗暴算粗暴... 查看详情
java使用webuploader做大文件的分块和断点续传
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。第一步:前端修改由于项目使用的是BJUI前端框架,并... 查看详情
b/s之大文件分段上传断点续传
...这些基于脚本语言实现的上传功能模块性能很弱,一是不支持2GB以上的内容上传;二是无法支持断点续传;三是效率极低,单台服务器最多支持几十个并发上传连接。当前我们要搭建一个运营级的视频服务平台,在尝试了各种产... 查看详情