parent
1469ca1cea
commit
b052ef6642
@ -0,0 +1,32 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.core.download.m3u8; |
||||
|
||||
/** |
||||
* M3U8 bandWidth 码率url转换器,对于某些服务器,返回的ts地址可以是相对地址,也可能是处理过的, |
||||
* 对于这种情况,你需要使用url转换器将地址转换为可正常访问的http地址 |
||||
*/ |
||||
public interface IBandWidthUrlConverter { |
||||
|
||||
/** |
||||
* 转换码率地址为可用的http地址,对于某些服务器,返回的切片信息有可能是相对地址,也可能是处理过的, |
||||
* 对于这种情况,你需要使用url转换器将地址转换为可正常访问的http地址 |
||||
* |
||||
* @param bandWidthUrl 原始码率地址 |
||||
* @return 可正常访问的http地址 |
||||
*/ |
||||
String convert(String bandWidthUrl); |
||||
} |
@ -0,0 +1,32 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.core.download.m3u8; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Ts文件合并处理,如果你希望使用自行处理ts文件的合并,你可以实现该接口 |
||||
*/ |
||||
public interface ITsMergeHandler { |
||||
|
||||
/** |
||||
* 合并ts文件 |
||||
* |
||||
* @param tsPath ts文件列表 |
||||
* @return {@code true} 合并成功 |
||||
*/ |
||||
boolean merge(List<String> tsPath); |
||||
} |
@ -1,140 +0,0 @@ |
||||
///*
|
||||
// * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
// *
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * Unless required by applicable law or agreed to in writing, software
|
||||
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// * See the License for the specific language governing permissions and
|
||||
// * limitations under the License.
|
||||
// */
|
||||
//package com.arialyy.aria.core.download.m3u8;
|
||||
//
|
||||
//import android.os.Bundle;
|
||||
//import android.os.Looper;
|
||||
//import android.os.Message;
|
||||
//import com.arialyy.aria.core.common.IThreadState;
|
||||
//import com.arialyy.aria.core.common.TaskRecord;
|
||||
//import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
//import com.arialyy.aria.core.inf.IEventListener;
|
||||
//import com.arialyy.aria.exception.BaseException;
|
||||
//import com.arialyy.aria.util.ALog;
|
||||
//
|
||||
///**
|
||||
// * M3U8线程状态管理
|
||||
// */
|
||||
//public class M3U8ThreadStateManager implements IThreadState {
|
||||
// private final String TAG = "M3U8ThreadStateManager";
|
||||
//
|
||||
// /**
|
||||
// * 任务状态回调
|
||||
// */
|
||||
// private IEventListener mListener;
|
||||
// private int mThreadNum; // 启动的线程总数
|
||||
// private int mCancelNum = 0; // 已经取消的线程的数
|
||||
// private int mStopNum = 0; // 已经停止的线程数
|
||||
// private int mFailNum = 0; // 失败的线程数
|
||||
// private int mCompleteNum = 0; // 完成的线程数
|
||||
// private long mProgress; //当前总进度
|
||||
// private TaskRecord mTaskRecord; // 任务记录
|
||||
// private Looper mLooper;
|
||||
//
|
||||
// /**
|
||||
// * @param taskRecord 任务记录
|
||||
// * @param listener 任务事件
|
||||
// */
|
||||
// M3U8ThreadStateManager(Looper looper, TaskRecord taskRecord, IEventListener listener) {
|
||||
// mLooper = looper;
|
||||
// mTaskRecord = taskRecord;
|
||||
// mThreadNum = mTaskRecord.threadNum;
|
||||
// mListener = listener;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 退出looper循环
|
||||
// */
|
||||
// private void quitLooper() {
|
||||
// mLooper.quit();
|
||||
// }
|
||||
//
|
||||
// @Override public boolean handleMessage(Message msg) {
|
||||
// switch (msg.what) {
|
||||
// case STATE_STOP:
|
||||
// mStopNum++;
|
||||
// if (isStop()) {
|
||||
// mListener.onStop(mProgress);
|
||||
// quitLooper();
|
||||
// }
|
||||
// break;
|
||||
// case STATE_CANCEL:
|
||||
// mCancelNum++;
|
||||
// if (isCancel()) {
|
||||
// ALog.d(TAG, "icCancel");
|
||||
// mListener.onCancel();
|
||||
// quitLooper();
|
||||
// }
|
||||
// break;
|
||||
// case STATE_FAIL:
|
||||
// mFailNum++;
|
||||
// if (isFail()) {
|
||||
// Bundle b = msg.getData();
|
||||
// mListener.onFail(b.getBoolean(KEY_RETRY, true),
|
||||
// (BaseException) b.getSerializable(KEY_ERROR_INFO));
|
||||
// quitLooper();
|
||||
// }
|
||||
// break;
|
||||
// case STATE_COMPLETE:
|
||||
// mCompleteNum++;
|
||||
// if (isComplete()) {
|
||||
// ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
// if (mTaskRecord.isBlock) {
|
||||
// if (mergeFile()) {
|
||||
// mListener.onComplete();
|
||||
// } else {
|
||||
// mListener.onFail(false, null);
|
||||
// }
|
||||
// } else {
|
||||
// mListener.onComplete();
|
||||
// }
|
||||
// quitLooper();
|
||||
// }
|
||||
// break;
|
||||
// case STATE_RUNNING:
|
||||
// mProgress += (long) msg.obj;
|
||||
// break;
|
||||
// case STATE_UPDATE_PROGRESS:
|
||||
// if (msg.obj == null) {
|
||||
// mProgress = updateBlockProgress();
|
||||
// } else {
|
||||
// mProgress = (long) msg.obj;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isStop() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isFail() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isComplete() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public boolean isCancel() {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public long getCurrentProgress() {
|
||||
// return mProgress;
|
||||
// }
|
||||
//}
|
@ -0,0 +1,380 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.util; |
||||
|
||||
import android.text.TextUtils; |
||||
import com.arialyy.aria.core.common.RecordHandler; |
||||
import com.arialyy.aria.core.common.RecordWrapper; |
||||
import com.arialyy.aria.core.common.TaskRecord; |
||||
import com.arialyy.aria.core.common.ThreadRecord; |
||||
import com.arialyy.aria.core.download.DownloadEntity; |
||||
import com.arialyy.aria.core.download.DownloadGroupEntity; |
||||
import com.arialyy.aria.core.download.m3u8.M3U8FileLoader; |
||||
import com.arialyy.aria.core.inf.AbsEntity; |
||||
import com.arialyy.aria.core.inf.AbsNormalEntity; |
||||
import com.arialyy.aria.core.upload.UploadEntity; |
||||
import com.arialyy.aria.orm.DbEntity; |
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 任务记录处理工具 |
||||
*/ |
||||
public class RecordUtil { |
||||
private static final String TAG = "RecordUtil"; |
||||
|
||||
/** |
||||
* 删除任务组记录 |
||||
* |
||||
* @param removeFile {@code true} 无论任务是否完成,都会删除记录和文件; |
||||
* {@code false} 如果任务已经完成,则只删除记录,不删除文件;任务未完成,记录和文件都会删除。 |
||||
*/ |
||||
public static void delGroupTaskRecord(String groupHash, boolean removeFile) { |
||||
if (TextUtils.isEmpty(groupHash)) { |
||||
ALog.e(TAG, "删除下载任务组记录失败,groupHash为null"); |
||||
return; |
||||
} |
||||
DownloadGroupEntity groupEntity = DbDataHelper.getDGEntity(groupHash); |
||||
|
||||
delGroupTaskRecord(groupEntity, removeFile, true); |
||||
} |
||||
|
||||
/** |
||||
* 删除任务组记录 |
||||
* |
||||
* @param removeFile {@code true} 无论任务是否完成,都会删除记录和文件; |
||||
* {@code false} 如果任务已经完成,则只删除记录,不删除文件;任务未完成,记录和文件都会删除。 |
||||
*/ |
||||
public static void delGroupTaskRecord(DownloadGroupEntity groupEntity, boolean removeFile, |
||||
boolean removeEntity) { |
||||
if (groupEntity == null) { |
||||
ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null"); |
||||
return; |
||||
} |
||||
List<RecordWrapper> records = |
||||
DbEntity.findRelationData(RecordWrapper.class, "dGroupHash=?", groupEntity.getGroupHash()); |
||||
|
||||
if (records == null || records.isEmpty()) { |
||||
ALog.w(TAG, "组任务记录删除失败,记录为null"); |
||||
} else { |
||||
for (RecordWrapper record : records) { |
||||
if (record == null || record.taskRecord == null) { |
||||
continue; |
||||
} |
||||
// 删除分块文件
|
||||
if (record.taskRecord.isBlock) { |
||||
for (int i = 0, len = record.taskRecord.threadNum; i < len; i++) { |
||||
File partFile = |
||||
new File(String.format(RecordHandler.SUB_PATH, record.taskRecord.filePath, i)); |
||||
if (partFile.exists()) { |
||||
partFile.delete(); |
||||
} |
||||
} |
||||
} |
||||
DbEntity.deleteData(ThreadRecord.class, "key=?", record.taskRecord.filePath); |
||||
record.taskRecord.deleteData(); |
||||
} |
||||
} |
||||
|
||||
List<DownloadEntity> subs = groupEntity.getSubEntities(); |
||||
if (subs != null) { |
||||
for (DownloadEntity sub : subs) { |
||||
File file = new File(sub.getFilePath()); |
||||
if (file.exists() && (removeFile || !sub.isComplete())) { |
||||
file.delete(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 删除文件夹
|
||||
if (!TextUtils.isEmpty(groupEntity.getDirPath())) { |
||||
File dir = new File(groupEntity.getDirPath()); |
||||
if (dir.exists() && (removeFile || !groupEntity.isComplete())) { |
||||
dir.delete(); |
||||
} |
||||
} |
||||
if (removeEntity) { |
||||
DbEntity.deleteData(DownloadEntity.class, "groupHash=?", groupEntity.getGroupHash()); |
||||
DbEntity.deleteData(DownloadGroupEntity.class, "groupHash=?", groupEntity.getGroupHash()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除任务记录,默认删除文件 |
||||
* |
||||
* @param removeFile {@code true} 无论任务是否完成,都会删除记录和文件; |
||||
* {@code false} 如果是下载任务,并且任务已经完成,则只删除记录,不删除文件;任务未完成,记录和文件都会删除。 |
||||
* 如果是上传任务,无论任务是否完成,都只删除记录 |
||||
*/ |
||||
public static void delTaskRecord(AbsNormalEntity entity, boolean removeFile) { |
||||
if (entity == null) return; |
||||
String filePath; |
||||
int type; |
||||
if (entity instanceof DownloadEntity) { |
||||
type = RecordHandler.TYPE_DOWNLOAD; |
||||
filePath = ((DownloadEntity) entity).getDownloadPath(); |
||||
} else if (entity instanceof UploadEntity) { |
||||
type = RecordHandler.TYPE_UPLOAD; |
||||
filePath = ((UploadEntity) entity).getFilePath(); |
||||
} else { |
||||
ALog.w(TAG, "删除记录失败,未知类型"); |
||||
return; |
||||
} |
||||
File targetFile = new File(filePath); |
||||
TaskRecord record = getTaskRecord(filePath); |
||||
if (record == null) { |
||||
if (removeFile) { |
||||
removeTargetFile(targetFile); |
||||
} |
||||
removeRecord(filePath); |
||||
removeEntity(type, filePath); |
||||
return; |
||||
} |
||||
|
||||
/* |
||||
* 处理任务未完成的情况 |
||||
*/ |
||||
if (!entity.isComplete()) { |
||||
if (record.taskType == TaskRecord.TYPE_M3U8) { // 删除ts分片文件
|
||||
String cacheDir = null; |
||||
if (!targetFile.isDirectory()) { |
||||
cacheDir = targetFile.getParent() + "/." + targetFile.getName(); |
||||
} |
||||
removeTsCache(record, cacheDir); |
||||
} else if (record.isBlock) { // 删除分块文件
|
||||
removeBlockFile(record); |
||||
} |
||||
} else if (removeFile) { // 处理任务完成情况
|
||||
removeTargetFile(targetFile); |
||||
} |
||||
|
||||
// 成功与否都将删除记录
|
||||
removeRecord(filePath); |
||||
} |
||||
|
||||
/** |
||||
* 删除任务记录,默认删除文件 |
||||
* |
||||
* @param filePath 文件路径 |
||||
* @param removeFile {@code true} 无论任务是否完成,都会删除记录和文件; |
||||
* {@code false} 如果是下载任务,并且任务已经完成,则只删除记录,不删除文件;任务未完成,记录和文件都会删除。 |
||||
* 如果是上传任务,无论任务是否完成,都只删除记录 |
||||
* @param type {@link RecordHandler#TYPE_DOWNLOAD}下载任务的记录,{@link RecordHandler#TYPE_UPLOAD} |
||||
* 上传任务的记录 |
||||
* @param removeEntity {@code true} 删除任务实体, |
||||
*/ |
||||
public static void delTaskRecord(String filePath, int type, boolean removeFile, |
||||
boolean removeEntity) { |
||||
if (TextUtils.isEmpty(filePath)) { |
||||
throw new NullPointerException("删除记录失败,文件路径为空"); |
||||
} |
||||
if (type != RecordHandler.TYPE_DOWNLOAD && type != RecordHandler.TYPE_UPLOAD) { |
||||
throw new IllegalArgumentException("任务记录类型错误"); |
||||
} |
||||
|
||||
AbsEntity entity; |
||||
if (type == RecordHandler.TYPE_DOWNLOAD) { |
||||
entity = DbEntity.findFirst(DownloadEntity.class, "downloadPath=?", filePath); |
||||
} else { |
||||
entity = DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath); |
||||
} |
||||
File targetFile = new File(filePath); |
||||
TaskRecord record = getTaskRecord(filePath); |
||||
if (entity == null || record == null) { |
||||
if (removeFile) { |
||||
removeTargetFile(targetFile); |
||||
} |
||||
removeRecord(filePath); |
||||
removeEntity(type, filePath); |
||||
return; |
||||
} |
||||
|
||||
/* |
||||
* 处理任务未完成的情况 |
||||
*/ |
||||
if (!entity.isComplete()) { |
||||
if (record.taskType == TaskRecord.TYPE_M3U8) { // 删除ts分片文件
|
||||
String cacheDir = null; |
||||
if (!targetFile.isDirectory()) { |
||||
cacheDir = targetFile.getParent() + "/." + targetFile.getName(); |
||||
} |
||||
removeTsCache(record, cacheDir); |
||||
} else if (record.isBlock) { // 删除分块文件
|
||||
removeBlockFile(record); |
||||
} |
||||
} else if (removeFile) { // 处理任务完成情况
|
||||
removeTargetFile(targetFile); |
||||
} |
||||
|
||||
// 成功与否都将删除记录
|
||||
removeRecord(filePath); |
||||
|
||||
if (removeEntity) { |
||||
removeEntity(type, filePath); |
||||
} |
||||
} |
||||
|
||||
private static void removeTargetFile(File targetFile) { |
||||
if (targetFile.exists()) { |
||||
targetFile.delete(); |
||||
} |
||||
} |
||||
|
||||
private static void removeRecord(String filePath) { |
||||
DbEntity.deleteData(ThreadRecord.class, "key=?", filePath); |
||||
DbEntity.deleteData(TaskRecord.class, "filePath=?", filePath); |
||||
} |
||||
|
||||
/** |
||||
* 删除实体 |
||||
* |
||||
* @param type {@link RecordHandler#TYPE_DOWNLOAD}下载任务的记录,{@link RecordHandler#TYPE_UPLOAD} |
||||
* 上传任务的记录 |
||||
*/ |
||||
private static void removeEntity(int type, String filePath) { |
||||
if (type == RecordHandler.TYPE_DOWNLOAD) { |
||||
DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath); |
||||
} else { |
||||
DbEntity.deleteData(UploadEntity.class, "filePath=?", filePath); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 根据文件路径获取任务记录 |
||||
*/ |
||||
private static TaskRecord getTaskRecord(String filePath) { |
||||
List<RecordWrapper> recordWrapper = |
||||
DbEntity.findRelationData(RecordWrapper.class, "filePath=?", filePath); |
||||
if (recordWrapper == null |
||||
|| recordWrapper.isEmpty() |
||||
|| recordWrapper.get(0) == null |
||||
|| recordWrapper.get(0).taskRecord == null) { |
||||
return null; |
||||
} else { |
||||
return recordWrapper.get(0).taskRecord; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除多线程分块下载的分块文件 |
||||
*/ |
||||
private static void removeBlockFile(TaskRecord record) { |
||||
for (int i = 0, len = record.threadNum; i < len; i++) { |
||||
File partFile = new File(String.format(RecordHandler.SUB_PATH, record.filePath, i)); |
||||
if (partFile.exists()) { |
||||
partFile.delete(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除ts文件 |
||||
*/ |
||||
private static void removeTsCache(TaskRecord record, String cacheDir) { |
||||
|
||||
if (!TextUtils.isEmpty(cacheDir)) { |
||||
List<String> partPath = new ArrayList<>(); |
||||
for (ThreadRecord tr : record.threadRecords) { |
||||
partPath.add(M3U8FileLoader.getTsFilePath(cacheDir, tr.threadId)); |
||||
} |
||||
for (String pp : partPath) { |
||||
File f = new File(pp); |
||||
if (f.exists()) { |
||||
f.delete(); |
||||
} |
||||
} |
||||
File cDir = new File(cacheDir); |
||||
if (cDir.exists()) { |
||||
cDir.delete(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除任务记录,默认删除文件,删除任务实体 |
||||
* |
||||
* @param filePath 文件路径 |
||||
* @param type {@link RecordHandler#TYPE_DOWNLOAD}下载任务的记录,{@link RecordHandler#TYPE_UPLOAD} |
||||
* 上传任务的记录 |
||||
*/ |
||||
public static void delTaskRecord(String filePath, int type) { |
||||
delTaskRecord(filePath, type, false, true); |
||||
} |
||||
|
||||
/** |
||||
* 修改任务路径,修改文件路径和任务记录信息。如果是分块任务,则修改分块文件的路径。 |
||||
* |
||||
* @param oldPath 旧的文件路径 |
||||
* @param newPath 新的文件路径 |
||||
*/ |
||||
public static void modifyTaskRecord(String oldPath, String newPath) { |
||||
if (oldPath.equals(newPath)) { |
||||
ALog.w(TAG, "修改任务记录失败,新文件路径和旧文件路径一致"); |
||||
return; |
||||
} |
||||
TaskRecord record = DbDataHelper.getTaskRecord(oldPath); |
||||
if (record == null) { |
||||
if (new File(oldPath).exists()) { |
||||
ALog.w(TAG, "修改任务记录失败,文件【" + oldPath + "】对应的任务记录不存在"); |
||||
} |
||||
return; |
||||
} |
||||
if (!record.isBlock) { |
||||
File oldFile = new File(oldPath); |
||||
if (oldFile.exists()) { |
||||
oldFile.renameTo(new File(newPath)); |
||||
} |
||||
} |
||||
|
||||
record.filePath = newPath; |
||||
record.update(); |
||||
// 修改线程记录
|
||||
if (record.threadRecords != null && !record.threadRecords.isEmpty()) { |
||||
for (ThreadRecord tr : record.threadRecords) { |
||||
tr.key = newPath; |
||||
File blockFile = new File(String.format(RecordHandler.SUB_PATH, oldPath, tr.threadId)); |
||||
if (blockFile.exists()) { |
||||
blockFile.renameTo(new File(String.format(RecordHandler.SUB_PATH, newPath, tr.threadId))); |
||||
} |
||||
} |
||||
DbEntity.updateManyData(record.threadRecords); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 检查分块任务是否存在 |
||||
* |
||||
* @param filePath 文件保存路径 |
||||
* @return {@code true} 分块文件存在 |
||||
*/ |
||||
public static boolean blockTaskExists(String filePath) { |
||||
return new File(String.format(RecordHandler.SUB_PATH, filePath, 0)).exists(); |
||||
} |
||||
|
||||
/** |
||||
* 获取分块文件的快大小 |
||||
* |
||||
* @param fileLen 文件总长度 |
||||
* @param blockId 分块id |
||||
* @param blockNum 分块数量 |
||||
* @return 分块长度 |
||||
*/ |
||||
public static long getBlockLen(long fileLen, int blockId, int blockNum) { |
||||
final long averageLen = fileLen / blockNum; |
||||
return blockId == blockNum - 1 ? (fileLen - blockId * averageLen) : averageLen; |
||||
} |
||||
} |
Loading…
Reference in new issue