Files
Aria/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java

1254 lines
36 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import android.util.Base64;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.group.AbsGroupCmd;
import com.arialyy.aria.core.command.group.GroupCmdFactory;
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.AbsFileer;
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.inf.AbsGroupTaskWrapper;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.orm.DbEntity;
import dalvik.system.DexFile;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by lyy on 2016/1/22. 通用工具
*/
public class CommonUtil {
private static final String TAG = "CommonUtil";
/**
* 检查分块任务是否存在
*
* @param filePath 文件保存路径
* @return {@code true} 分块文件存在
*/
public static boolean blockTaskExists(String filePath) {
return new File(String.format(AbsFileer.SUB_PATH, filePath, 0)).exists();
}
/**
* 删除文件
*
* @param path 文件路径
* @return {@code true}删除成功、{@code false}删除失败
*/
public static boolean deleteFile(String path) {
if (TextUtils.isEmpty(path)) {
ALog.e(TAG, "删除文件失败,路径为空");
return false;
}
File file = new File(path);
if (file.exists()) {
final File to = new File(file.getAbsolutePath() + System.currentTimeMillis());
if (file.renameTo(to)) {
return to.delete();
} else {
return file.delete();
}
}
return false;
}
/**
* 将对象写入文件
*
* @param filePath 文件路径
* @param data data数据必须实现{@link Serializable}接口
*/
public static void writeObjToFile(String filePath, Object data) {
if (!(data instanceof Serializable)) {
ALog.e(TAG, "对象写入文件失败data数据必须实现Serializable接口");
return;
}
FileOutputStream ops = null;
try {
if (!createFile(filePath)) {
return;
}
ops = new FileOutputStream(filePath);
ObjectOutputStream oops = new ObjectOutputStream(ops);
oops.writeObject(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ops != null) {
try {
ops.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 从文件中读取对象
*
* @param filePath 文件路径
* @return 如果读取成功返回相应的Obj对象读取失败返回null
*/
public static Object readObjFromFile(String filePath) {
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "文件路径为空");
return null;
}
File file = new File(filePath);
if (!file.exists()) {
ALog.e(TAG, String.format("文件【%s】不存在", filePath));
return null;
}
FileInputStream fis = null;
try {
fis = new FileInputStream(filePath);
ObjectInputStream oois = new ObjectInputStream(fis);
return oois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* 获取分块文件的快大小
*
* @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;
}
/**
* 检查SD内存空间是否充足
*
* @param filePath 文件保存路径
* @param fileSize 文件大小
* @return {@code false} 内存空间不足,{@code true}内存空间足够
*/
public static boolean checkSDMemorySpace(String filePath, long fileSize) {
List<String> dirs = FileUtil.getSDPathList(AriaManager.APP);
if (dirs == null || dirs.isEmpty()) {
return true;
}
for (String path : dirs) {
if (filePath.contains(path)) {
if (fileSize > 0 && fileSize > getAvailableExternalMemorySize(path)) {
return false;
}
}
}
return true;
}
/**
* sdcard 可用大小
*
* @param sdcardPath sdcard 根路径
* @return 单位为byte
*/
public static long getAvailableExternalMemorySize(String sdcardPath) {
StatFs stat = new StatFs(sdcardPath);
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
/**
* sdcard 总大小
*
* @param sdcardPath sdcard 根路径
* @return 单位为byte
*/
public static long getTotalExternalMemorySize(String sdcardPath) {
StatFs stat = new StatFs(sdcardPath);
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
/**
* 获取某包下所有类
*
* @param className 过滤的类名
* @return 类的完整名称
*/
public static List<String> getPkgClassNames(Context context, String className) {
List<String> classNameList = new ArrayList<>();
String pPath = context.getPackageCodePath();
File dir = new File(pPath).getParentFile();
String[] paths = dir.list();
if (paths == null) {
classNameList.addAll(getPkgClassName(pPath, className));
} else {
String dPath = dir.getPath();
for (String path : dir.list()) {
String fPath = dPath + "/" + path;
if (!fPath.endsWith(".apk")) {
continue;
}
classNameList.addAll(getPkgClassName(fPath, className));
}
}
return classNameList;
}
/**
* 获取指定包名下的所有类
*
* @param path dex路径
* @param filterClass 需要过滤的类
*/
public static List<String> getPkgClassName(String path, String filterClass) {
List<String> list = new ArrayList<>();
try {
File file = new File(path);
if (!file.exists()) {
ALog.w(TAG, String.format("路径【%s】下的Dex文件不存在", path));
return list;
}
DexFile df = new DexFile(path);//通过DexFile查找当前的APK中可执行文件
Enumeration<String> enumeration = df.entries();//获取df中的元素 这里包含了所有可执行的类名 该类名包含了包名+类名的方式
while (enumeration.hasMoreElements()) {
String _className = enumeration.nextElement();
if (!_className.contains(filterClass)) {
continue;
}
if (_className.contains(filterClass)) {
list.add(_className);
}
}
df.close();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
/**
* 拦截window.location.replace数据
*
* @return 重定向url
*/
public static String getWindowReplaceUrl(String text) {
if (TextUtils.isEmpty(text)) {
ALog.e(TAG, "拦截数据为null");
return null;
}
String reg = Regular.REG_WINLOD_REPLACE;
Pattern p = Pattern.compile(reg);
Matcher m = p.matcher(text);
if (m.find()) {
String s = m.group();
s = s.substring(9, s.length() - 2);
return s;
}
return null;
}
/**
* 获取sdcard app的缓存目录
*
* @return "/mnt/sdcard/Android/data/{package_name}/files/"
*/
public static String getAppPath(Context context) {
//判断是否存在sd卡
boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(
android.os.Environment.getExternalStorageState());
if (!sdExist) {
return null;
} else {
//获取sd卡路径
File file = context.getExternalFilesDir(null);
String dir;
if (file != null) {
dir = file.getPath() + "/";
} else {
dir = Environment.getExternalStorageDirectory().getPath()
+ "/Android/data/"
+ context.getPackageName()
+ "/files/";
}
return dir;
}
}
/**
* 获取map泛型类型
*
* @param map list类型字段
* @return 泛型类型
*/
public static Class[] getMapParamType(Field map) {
Class type = map.getType();
if (!type.isAssignableFrom(Map.class)) {
ALog.d(TAG, "字段类型不是Map");
return null;
}
Type fc = map.getGenericType();
if (fc == null) {
ALog.d(TAG, "该字段没有泛型参数");
return null;
}
if (fc instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) fc;
Type[] types = pt.getActualTypeArguments();
Class[] clazz = new Class[2];
clazz[0] = (Class) types[0];
clazz[1] = (Class) types[1];
return clazz;
}
return null;
}
/**
* 获取list泛型类型
*
* @param list list类型字段
* @return 泛型类型
*/
public static Class getListParamType(Field list) {
Class type = list.getType();
if (!type.isAssignableFrom(List.class)) {
ALog.d(TAG, "字段类型不是List");
return null;
}
Type fc = list.getGenericType(); // 关键的地方如果是List类型得到其Generic的类型
if (fc == null) {
ALog.d(TAG, "该字段没有泛型参数");
return null;
}
if (fc instanceof ParameterizedType) { //如果是泛型参数的类型
ParameterizedType pt = (ParameterizedType) fc;
return (Class) pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象。
}
return null;
}
/**
* 创建文件名如果url链接有后缀名则使用url中的后缀名
*
* @return url 的 hashKey
*/
public static String createFileName(String url) {
int end = url.indexOf("?");
String tempUrl, fileName = "";
if (end > 0) {
tempUrl = url.substring(0, end);
int tempEnd = tempUrl.lastIndexOf("/");
if (tempEnd > 0) {
fileName = tempUrl.substring(tempEnd + 1);
}
} else {
int tempEnd = url.lastIndexOf("/");
if (tempEnd > 0) {
fileName = url.substring(tempEnd + 1);
}
}
if (TextUtils.isEmpty(fileName)) {
fileName = CommonUtil.keyToHashKey(url);
}
return fileName;
}
/**
* 分割获取url协议ip/域名,端口,内容
*
* @param url 输入的url{@code String url = "ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3终极之战BD国英双语中英双字.mkv";}
*/
public static FtpUrlEntity getFtpUrlInfo(String url) {
Uri uri = Uri.parse(url);
String userInfo = uri.getUserInfo(), remotePath = uri.getPath();
ALog.d(TAG,
String.format("scheme = %s, user = %s, host = %s, port = %s, path = %s", uri.getScheme(),
userInfo, uri.getHost(), uri.getPort(), remotePath));
FtpUrlEntity entity = new FtpUrlEntity();
entity.url = url;
entity.hostName = uri.getHost();
entity.port = uri.getPort() == -1 ? "21" : String.valueOf(uri.getPort());
if (!TextUtils.isEmpty(userInfo)) {
String[] temp = userInfo.split(":");
if (temp.length == 2) {
entity.user = temp[0];
entity.password = temp[1];
} else {
entity.user = userInfo;
}
}
entity.scheme = uri.getScheme();
entity.remotePath = TextUtils.isEmpty(remotePath) ? "/" : remotePath;
return entity;
}
/**
* 转换Url
*
* @param url 原地址
* @return 转换后的地址
*/
public static String convertUrl(String url) {
Uri uri = Uri.parse(url);
url = uri.toString();
if (hasDoubleCharacter(url)) {
//预先处理空格URLEncoder只会把空格转换为+
url = url.replaceAll(" ", "%20");
//匹配双字节字符(包括汉字在内)
String regex = Regular.REG_DOUBLE_CHAR_AND_SPACE;
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(url);
Set<String> strs = new HashSet<>();
while (m.find()) {
strs.add(m.group());
}
try {
for (String str : strs) {
url = url.replaceAll(str, URLEncoder.encode(str, "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return url;
}
/**
* 判断是否有双字节字符(包括汉字在内) 和空格、制表符、回车
*
* @param chineseStr 需要进行判断的字符串
* @return {@code true}有双字节字符,{@code false} 无双字节字符
*/
public static boolean hasDoubleCharacter(String chineseStr) {
char[] charArray = chineseStr.toCharArray();
for (char aCharArray : charArray) {
if (((aCharArray >= 0x0391) && (aCharArray <= 0xFFE5)) || (aCharArray == 0x0d) || (aCharArray
== 0x0a) || (aCharArray == 0x20)) {
return true;
}
}
return false;
}
/**
* base64 解密字符串
*
* @param str 被加密的字符串
* @return 解密后的字符串
*/
public static String decryptBASE64(String str) {
return new String(Base64.decode(str.getBytes(), Base64.DEFAULT));
}
/**
* base64 加密字符串
*
* @param str 需要加密的字符串
* @return 加密后的字符串
*/
public static String encryptBASE64(String str) {
return Base64.encodeToString(str.getBytes(), Base64.DEFAULT);
}
/**
* 字符串编码转换
*/
public static String strCharSetConvert(String oldStr, String charSet) {
try {
return new String(oldStr.getBytes(), charSet);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据下载任务组的url创建key
*
* @return urls 为 null 或者 size为0返回""
*/
public static String getMd5Code(List<String> urls) {
if (urls == null || urls.size() < 1) return "";
String md5 = "";
StringBuilder sb = new StringBuilder();
for (String url : urls) {
sb.append(url);
}
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(sb.toString().getBytes());
md5 = new BigInteger(1, md.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
ALog.e(TAG, e.getMessage());
}
return md5;
}
/**
* 获取字符串的md5
*
* @return 字符串为空或获取md5失败则返回""
*/
public static String getStrMd5(String str) {
if (TextUtils.isEmpty(str)) return "";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
return new BigInteger(1, md.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
ALog.e(TAG, e.getMessage());
}
return "";
}
/**
* 删除任务组记录
*
* @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(AbsFileer.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.getDownloadPath());
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 dEntity, boolean removeFile) {
if (dEntity == null) return;
String filePath;
int type;
if (dEntity instanceof DownloadEntity) {
type = 1;
filePath = ((DownloadEntity) dEntity).getDownloadPath();
} else if (dEntity instanceof UploadEntity) {
type = 2;
filePath = ((UploadEntity) dEntity).getFilePath();
} else {
ALog.w(TAG, "删除记录失败,未知类型");
return;
}
delTaskRecord(filePath, type, removeFile, true);
}
/**
* 删除任务记录,默认删除文件
*
* @param filePath 文件路径
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件 {@code false}如果任务已经完成,只删除任务数据库记录
* @param type {@code 1}下载任务的记录,{@code 2} 上传任务的记录 {@code false}如果任务已经完成,只删除任务数据库记录
* @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 != 1 && type != 2) {
throw new IllegalArgumentException("任务记录类型错误");
}
List<RecordWrapper> recordWrapper =
DbEntity.findRelationData(RecordWrapper.class, "filePath=?", filePath);
DbEntity.deleteData(ThreadRecord.class, "key=?", filePath); // 必须先获取完成数据再删除线程记录
File file = new File(filePath);
if (recordWrapper == null
|| recordWrapper.isEmpty()
|| recordWrapper.get(0) == null
|| recordWrapper.get(0).taskRecord == null) {
ALog.w(TAG, "记录为空");
} else {
TaskRecord record = recordWrapper.get(0).taskRecord;
// 删除分块文件
if (record.isBlock) {
for (int i = 0, len = record.threadNum; i < len; i++) {
File partFile = new File(String.format(AbsFileer.SUB_PATH, record.filePath, i));
if (partFile.exists()) {
partFile.delete();
}
}
}
// 删除任务记录
record.deleteData();
}
if (file.exists() && removeFile) {
file.delete();
}
if (removeEntity) {
if (type == 1) {
DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath);
} else {
DbEntity.deleteData(UploadEntity.class, "filePath=?", filePath);
}
}
}
/**
* 删除任务记录,默认删除文件,删除任务实体
*
* @param filePath 文件路径
* @param type {@code 1}下载任务的记录,{@code 2} 上传任务的记录 {@code false}如果任务已经完成,只删除任务数据库记录
*/
public static void delTaskRecord(String filePath, int type) {
delTaskRecord(filePath, type, false, true);
}
/**
* 获取CPU核心数
*/
public static int getCoresNum() {
//Private Class to display only CPU devices in the directory listing
class CpuFilter implements FileFilter {
@Override public boolean accept(File pathname) {
//Check if filename is "cpu", followed by a single digit number
return Pattern.matches("cpu[0-9]", pathname.getName());
}
}
try {
//Get directory containing CPU info
File dir = new File("/sys/devices/system/cpu/");
//Filter to only list the devices we care about
File[] files = dir.listFiles(new CpuFilter());
ALog.d(TAG, "CPU Count: " + files.length);
//Return the number of cores (virtual CPU devices)
return files.length;
} catch (Exception e) {
//Print exception
ALog.d(TAG, "CPU Count: Failed.");
e.printStackTrace();
//Default to return 1 core
return 1;
}
}
/**
* 通过流创建文件
*/
public static void createFileFormInputStream(InputStream is, String path) {
try {
FileOutputStream fos = new FileOutputStream(path);
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) > 0) {
fos.write(buf, 0, len);
}
is.close();
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 校验文件MD5码
*/
public static boolean checkMD5(String md5, File updateFile) {
if (TextUtils.isEmpty(md5) || updateFile == null) {
ALog.e(TAG, "MD5 string empty or updateFile null");
return false;
}
String calculatedDigest = getFileMD5(updateFile);
if (calculatedDigest == null) {
ALog.e(TAG, "calculatedDigest null");
return false;
}
return calculatedDigest.equalsIgnoreCase(md5);
}
/**
* 校验文件MD5码
*/
public static boolean checkMD5(String md5, InputStream is) {
if (TextUtils.isEmpty(md5) || is == null) {
ALog.e(TAG, "MD5 string empty or updateFile null");
return false;
}
String calculatedDigest = getFileMD5(is);
if (calculatedDigest == null) {
ALog.e(TAG, "calculatedDigest null");
return false;
}
return calculatedDigest.equalsIgnoreCase(md5);
}
/**
* 获取文件MD5码
*/
public static String getFileMD5(File updateFile) {
InputStream is;
try {
is = new FileInputStream(updateFile);
} catch (FileNotFoundException e) {
ALog.e(TAG, e);
return null;
}
return getFileMD5(is);
}
/**
* 获取文件MD5码
*/
public static String getFileMD5(InputStream is) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
ALog.e(TAG, e);
return null;
}
byte[] buffer = new byte[8192];
int read;
try {
while ((read = is.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String output = bigInt.toString(16);
// Fill to 32 chars
output = String.format("%32s", output).replace(' ', '0');
return output;
} catch (IOException e) {
throw new RuntimeException("Unable to process file for MD5", e);
} finally {
try {
is.close();
} catch (IOException e) {
ALog.e(TAG, e);
}
}
}
/**
* 创建任务命令
*
* @param taskType {@link ICmd#TASK_TYPE_DOWNLOAD}、{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}、{@link
* ICmd#TASK_TYPE_UPLOAD}
*/
public static <T extends AbsTaskWrapper> AbsNormalCmd createNormalCmd(T entity, int cmd,
int taskType) {
return NormalCmdFactory.getInstance().createCmd(entity, cmd, taskType);
}
/**
* 创建任务组命令
*
* @param childUrl 子任务url
*/
public static <T extends AbsGroupTaskWrapper> AbsGroupCmd createGroupCmd(String target, T entity,
int cmd, String childUrl) {
return GroupCmdFactory.getInstance().createCmd(target, entity, cmd, childUrl);
}
/**
* 创建隐性的Intent
*/
public static Intent createIntent(String packageName, String action) {
Uri.Builder builder = new Uri.Builder();
builder.scheme(packageName);
Uri uri = builder.build();
Intent intent = new Intent(action);
intent.setData(uri);
return intent;
}
/**
* 存储字符串到配置文件
*
* @param preName 配置文件名
* @param key 存储的键值
* @param value 需要存储的字符串
* @return 成功标志
*/
public static Boolean putString(String preName, Context context, String key, String value) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pre.edit();
editor.putString(key, value);
return editor.commit();
}
/**
* 从配置文件读取字符串
*
* @param preName 配置文件名
* @param key 字符串键值
* @return 键值对应的字符串, 默认返回""
*/
public static String getString(String preName, Context context, String key) {
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
return pre.getString(key, "");
}
/**
* 获取所有字段,包括父类的字段
*/
public static List<Field> getAllFields(Class clazz) {
List<Field> fields = new ArrayList<>();
Class personClazz = clazz.getSuperclass();
if (personClazz != null) {
Class rootClazz = personClazz.getSuperclass();
if (rootClazz != null) {
Collections.addAll(fields, rootClazz.getDeclaredFields());
}
Collections.addAll(fields, personClazz.getDeclaredFields());
}
Collections.addAll(fields, clazz.getDeclaredFields());
return fields;
}
/**
* 获取当前类里面的所在字段
*/
public static Field[] getFields(Class clazz) {
Field[] fields;
fields = clazz.getDeclaredFields();
if (fields.length == 0) {
Class superClazz = clazz.getSuperclass();
if (superClazz != null) {
fields = getFields(superClazz);
}
}
return fields;
}
/**
* 获取类里面的指定对象,如果该类没有则从父类查询
*/
public static Field getField(Class clazz, String name) {
Field field = null;
try {
field = clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
try {
field = clazz.getField(name);
} catch (NoSuchFieldException e1) {
if (clazz.getSuperclass() == null) {
return field;
} else {
field = getField(clazz.getSuperclass(), name);
}
}
}
if (field != null) {
field.setAccessible(true);
}
return field;
}
/**
* 字符串转hashcode
*/
public static int keyToHashCode(String str) {
int total = 0;
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch == '-') ch = (char) 28; // does not contain the same last 5 bits as any letter
if (ch == '\'') ch = (char) 29; // nor this
total = (total * 33) + (ch & 0x1F);
}
return total;
}
/**
* 将key转换为16进制码
*
* @param key 缓存的key
* @return 转换后的key的值, 系统便是通过该key来读写缓存
*/
public static String keyToHashKey(String key) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
/**
* 将普通字符串转换为16位进制字符串
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (byte aSrc : src) {
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
/**
* 获取对象名
*
* @param obj 对象
* @return 对象名
*/
public static String getClassName(Object obj) {
String[] arrays = obj.getClass().getName().split("\\.");
return arrays[arrays.length - 1];
}
/**
* 获取对象名
*
* @param clazz clazz
* @return 对象名
*/
public static String getClassName(Class clazz) {
String[] arrays = clazz.getName().split("\\.");
return arrays[arrays.length - 1];
}
/**
* 格式化文件大小
*
* @param size file.length() 获取文件大小
*/
public static String formatFileSize(double size) {
if (size < 0) {
return "0kb";
}
double kiloByte = size / 1024;
if (kiloByte < 1) {
return size + "b";
}
double megaByte = kiloByte / 1024;
if (megaByte < 1) {
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "kb";
}
double gigaByte = megaByte / 1024;
if (gigaByte < 1) {
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "mb";
}
double teraBytes = gigaByte / 1024;
if (teraBytes < 1) {
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "gb";
}
BigDecimal result4 = new BigDecimal(teraBytes);
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "tb";
}
/**
* 创建目录 当目录不存在的时候创建文件否则返回false
*/
public static boolean createDir(String path) {
File file = new File(path);
if (!file.exists()) {
if (!file.mkdirs()) {
ALog.d(TAG, "创建失败,请检查路径和是否配置文件权限!");
return false;
}
return true;
}
return false;
}
/**
* 创建文件 当文件不存在的时候就创建一个文件。 如果文件存在,先删除原文件,然后重新创建一个新文件
*
* @return {@code true} 创建成功、{@code false} 创建失败
*/
public static boolean createFile(String path) {
if (TextUtils.isEmpty(path)) {
ALog.e(TAG, "文件路径不能为null");
return false;
}
File file = new File(path);
if (file.getParentFile() == null || !file.getParentFile().exists()) {
ALog.d(TAG, "目标文件所在路径不存在,准备创建……");
if (!createDir(file.getParent())) {
ALog.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "");
}
}
// 创建目标文件
if (file.exists()) {
final File to = new File(file.getAbsolutePath() + System.currentTimeMillis());
if (file.renameTo(to)) {
to.delete();
} else {
file.delete();
}
}
try {
if (file.createNewFile()) {
ALog.d(TAG, "创建文件成功:" + file.getAbsolutePath());
return true;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return false;
}
/**
* 通过文件名获取下载配置文件路径
*
* @param fileName 文件名
*/
public static String getFileConfigPath(boolean isDownload, String fileName) {
return AriaManager.APP.getFilesDir().getPath() + (isDownload ? AriaManager.DOWNLOAD_TEMP_DIR
: AriaManager.UPLOAD_TEMP_DIR) + fileName + ".properties";
}
/**
* 修改任务路径,修改文件路径和任务记录信息。如果是分块任务,则修改分块文件的路径。
*
* @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(AbsFileer.SUB_PATH, oldPath, tr.threadId));
if (blockFile.exists()) {
blockFile.renameTo(new File(String.format(AbsFileer.SUB_PATH, newPath, tr.threadId)));
}
}
DbEntity.updateManyData(record.threadRecords);
}
}
/**
* 读取下载配置文件
*/
public static Properties loadConfig(File file) {
Properties properties = new Properties();
FileInputStream fis = null;
if (!file.exists()) {
createFile(file.getPath());
}
try {
fis = new FileInputStream(file);
properties.load(fis);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return properties;
}
/**
* 保存配置文件
*/
public static void saveConfig(File file, Properties properties) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file, false);
properties.store(fos, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.flush();
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}