断点续传就是在下载资源过程中,网络出现中断后,下一次下载的时候能够接着上一次下载的地方继续下载,以达到节省流量及时间的效果。在Http1.1协议中默认支持获取文件的部分内容,这其中主要是通过头部的两个参数:Range和Content Range来实现的。客户端发请求时对应的是Range,服务器端响应时对应的是 Content-Range。
栗子如下:
@Entity(tableName = "BreakPointFileTable")
public class BreakPointFileTable {@PrimaryKey(autoGenerate = true)public long id;public String fileName;public String fileDownloadUrl;public String fileSavePath;public long fileLength;public long startDownloadProgress;public long currentDownloadProgress;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}public String getFileDownloadUrl() {return fileDownloadUrl;}public void setFileDownloadUrl(String fileDownloadUrl) {this.fileDownloadUrl = fileDownloadUrl;}public String getFileSavePath() {return fileSavePath;}public void setFileSavePath(String fileSavePath) {this.fileSavePath = fileSavePath;}public long getFileLength() {return fileLength;}public void setFileLength(long fileLength) {this.fileLength = fileLength;}public long getStartDownloadProgress() {return startDownloadProgress;}public void setStartDownloadProgress(long startDownloadProgress) {this.startDownloadProgress = startDownloadProgress;}public long getCurrentDownloadProgress() {return currentDownloadProgress;}public void setCurrentDownloadProgress(long currentDownloadProgress) {this.currentDownloadProgress = currentDownloadProgress;}}
public void download(final String url, final String fileName, final OnDownloadListener listener) {RandomAccessFile finalRandomFile = null;long downLoadFileLength = 0;long start = 0;File dir = createDir(FileTypeUtils.getFileType(fileName),getFileName(fileName));String name = fileName;File file = new File(dir, name);try {boolean fileDownloadExits = BreakPointDataBase.getDataBase().getResumeBreakPointDao().isFileDownloadExits(fileName);if (fileDownloadExits) {try {finalRandomFile = new RandomAccessFile(file, "rwd");List<BreakPointFileTable> allDownloadFileList = BreakPointDataBase.getDataBase().getResumeBreakPointDao().getDownloadFileByName(fileName);if(allDownloadFileList.size()>0) {start = allDownloadFileList.get(0).getStartDownloadProgress() + allDownloadFileList.get(0).getCurrentDownloadProgress();downLoadFileLength = allDownloadFileList.get(0).getFileLength();finalRandomFile.seek(start);}} catch (Exception e) {e.printStackTrace();}} else {file.createNewFile();finalRandomFile = new RandomAccessFile(file, "rwd");finalRandomFile.seek(0);BreakPointFileTable breakPointFileTable = new BreakPointFileTable();breakPointFileTable.setFileName(file.getName());breakPointFileTable.setFileDownloadUrl(url);breakPointFileTable.setStartDownloadProgress(0);breakPointFileTable.setCurrentDownloadProgress(0);breakPointFileTable.setFileSavePath(file.getPath());BreakPointDataBase.getDataBase().getResumeBreakPointDao().insertDownloadFileInfo(breakPointFileTable);}Request.Builder builder = new okhttp3.Request.Builder();builder.addHeader("Authorization", "Basic " + com.decard.utils.Base64Util.encode(String.format("%s:%s", userName, password).getBytes()));if(start > 0 && downLoadFileLength > 0) {// 断点续传关键builder.addHeader("RANGE", "bytes=" + start + "-" + downLoadFileLength);}RandomAccessFile fileOperator = finalRandomFile;okhttp3.Request request = builder.url(url).build();call = okHttpClient.newCall(request);long finalStart = start;long finalDownLoadFileLength = downLoadFileLength;call.enqueue(new okhttp3.Callback() {long tempCurrentProgress = 0;long tempFileLength = 0;@Overridepublic void onFailure(okhttp3.Call call, java.io.IOException e) {listener.onDownloadFailed();}@Overridepublic void onResponse(okhttp3.Call call, okhttp3.Response response) throws java.io.IOException {java.io.InputStream is = null;byte[] buf = new byte[1024*5];int len = 0;java.io.FileOutputStream fos = null;try {// 下载中处理// 下载完成BreakPointDataBase.getDataBase().getResumeBreakPointDao().deleteBreakPointFileInfo(BreakPointDataBase.getDataBase().getResumeBreakPointDao().getAllDownloadFileList());listener.onDownloadSuccess(file);} catch (Exception e) {// 网络异常 更新数据库BreakPointDataBase.getDataBase().getResumeBreakPointDao().updateDownloadFileProgress(url, tempCurrentProgress, tempFileLength);e.printStackTrace();listener.onDownloadFailed();} finally {...}}});} catch (Exception e) {e.printStackTrace();}}
注意: 在断点续传中 第一次能够获取文件总长度,续传过程中 获取的是文件部分长度,所以在计算进度时需要注意。