You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Android-Download/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java

1219 lines
35 KiB

/*
* 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.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(DownloadGroupEntity groupEntity, boolean removeFile) {
if (groupEntity == null) {
ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null");
return;
}
List<TaskRecord> records =
DbEntity.findDatas(TaskRecord.class, "dGroupHash=?", groupEntity.getGroupHash());
if (records == null || records.isEmpty()) {
ALog.w(TAG, "组任务记录删除失败,记录为null");
} else {
for (TaskRecord record : records) {
// 删除分块文件
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();
}
}
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();
}
groupEntity.deleteData();
}
}
/**
* 删除任务记录
*
* @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);
}
/**
* 删除任务记录,默认删除文件
*
* @param filePath 文件路径
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件 {@code false}如果任务已经完成,只删除任务数据库记录
* @param type {@code 1}下载任务的记录,{@code 2} 上传任务的记录 {@code false}如果任务已经完成,只删除任务数据库记录
*/
public static void delTaskRecord(String filePath, int type, boolean removeFile) {
if (TextUtils.isEmpty(filePath)) {
throw new NullPointerException("删除记录失败,文件路径为空");
}
if (type != 1 && type != 2) {
throw new IllegalArgumentException("任务记录类型错误");
}
TaskRecord record = DbEntity.findFirst(TaskRecord.class, "filePath=?", filePath);
DbEntity.deleteData(ThreadRecord.class, "key=?", filePath);
File file = new File(filePath);
if (record == null) {
ALog.w(TAG, "记录为空");
} else {
// 删除分块文件
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 (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);
}
/**
* 获取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 = null;
fields = clazz.getDeclaredFields();
if (fields == null || 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.saveAll(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();
}
}
}
}