|
|
@ -17,26 +17,43 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
package com.arialyy.aria.util; |
|
|
|
package com.arialyy.aria.util; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.app.ActivityManager; |
|
|
|
|
|
|
|
import android.content.Context; |
|
|
|
|
|
|
|
import android.os.Build; |
|
|
|
|
|
|
|
import android.os.Environment; |
|
|
|
|
|
|
|
import android.text.TextUtils; |
|
|
|
|
|
|
|
import java.io.BufferedReader; |
|
|
|
import java.io.File; |
|
|
|
import java.io.File; |
|
|
|
import java.io.FileInputStream; |
|
|
|
import java.io.FileInputStream; |
|
|
|
import java.io.FileNotFoundException; |
|
|
|
import java.io.FileNotFoundException; |
|
|
|
import java.io.FileOutputStream; |
|
|
|
import java.io.FileOutputStream; |
|
|
|
|
|
|
|
import java.io.FileReader; |
|
|
|
|
|
|
|
import java.io.FileWriter; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.SequenceInputStream; |
|
|
|
import java.io.SequenceInputStream; |
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.nio.channels.Channels; |
|
|
|
import java.nio.channels.Channels; |
|
|
|
import java.nio.channels.FileChannel; |
|
|
|
import java.nio.channels.FileChannel; |
|
|
|
import java.nio.channels.ReadableByteChannel; |
|
|
|
import java.nio.channels.ReadableByteChannel; |
|
|
|
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.Enumeration; |
|
|
|
import java.util.Enumeration; |
|
|
|
|
|
|
|
import java.util.LinkedHashMap; |
|
|
|
import java.util.LinkedList; |
|
|
|
import java.util.LinkedList; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
import java.util.Scanner; |
|
|
|
|
|
|
|
import java.util.regex.Pattern; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 文件操作工具类 |
|
|
|
* 文件操作工具类 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class FileUtil { |
|
|
|
public class FileUtil { |
|
|
|
private static final String TAG = "FileUtil"; |
|
|
|
private static final String TAG = "FileUtil"; |
|
|
|
|
|
|
|
private static final Pattern DIR_SEPORATOR = Pattern.compile("/"); |
|
|
|
|
|
|
|
private static final String EXTERNAL_STORAGE_PATH = |
|
|
|
|
|
|
|
Environment.getExternalStorageDirectory().getPath(); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 合并文件 |
|
|
|
* 合并文件 |
|
|
@ -148,4 +165,290 @@ public class FileUtil { |
|
|
|
e.printStackTrace(); |
|
|
|
e.printStackTrace(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 获取SD卡目录列表 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static List<String> getSDPathList(Context context) { |
|
|
|
|
|
|
|
List<String> paths; |
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { |
|
|
|
|
|
|
|
paths = getVolumeList(context); |
|
|
|
|
|
|
|
if (paths == null || paths.isEmpty()) { |
|
|
|
|
|
|
|
paths = getStorageDirectories(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { |
|
|
|
|
|
|
|
paths = getVolumeList(context); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
List<String> mounts = readMountsFile(); |
|
|
|
|
|
|
|
List<String> volds = readVoldFile(); |
|
|
|
|
|
|
|
paths = compareMountsWithVold(mounts, volds); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return paths; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* getSDPathList |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static List<String> getVolumeList(final Context context) { |
|
|
|
|
|
|
|
List<String> pathList = null; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
android.os.storage.StorageManager manager = |
|
|
|
|
|
|
|
(android.os.storage.StorageManager) context.getSystemService(Context.STORAGE_SERVICE); |
|
|
|
|
|
|
|
Method method = manager.getClass().getMethod("getVolumePaths"); |
|
|
|
|
|
|
|
String[] paths = (String[]) method.invoke(manager); |
|
|
|
|
|
|
|
pathList = Arrays.asList(paths); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
e.printStackTrace(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (pathList == null || pathList.isEmpty()) { |
|
|
|
|
|
|
|
pathList = new ArrayList<>(); |
|
|
|
|
|
|
|
pathList.add(EXTERNAL_STORAGE_PATH); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
LinkedHashMap<Integer, String> paths = new LinkedHashMap<>(); |
|
|
|
|
|
|
|
for (String path : pathList) { |
|
|
|
|
|
|
|
File root = new File(path); |
|
|
|
|
|
|
|
if (!root.exists() || !root.isDirectory() || !canWrite(path)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//去除mount的相同目录
|
|
|
|
|
|
|
|
int key = (root.getTotalSpace() + "-" + root.getUsableSpace()).hashCode(); |
|
|
|
|
|
|
|
String prevPath = paths.get(key); |
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(prevPath) && prevPath.length() < path.length()) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
paths.put(key, path); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<String> list = new ArrayList<>(); |
|
|
|
|
|
|
|
for (Integer key : paths.keySet()) { |
|
|
|
|
|
|
|
list.add(paths.get(key)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return list; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static boolean canWrite(String dirPath) { |
|
|
|
|
|
|
|
File dir = new File(dirPath); |
|
|
|
|
|
|
|
if (dir.canWrite()) { |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
boolean canWrite; |
|
|
|
|
|
|
|
File testWriteFile = null; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
testWriteFile = new File(dirPath, "tw.txt"); |
|
|
|
|
|
|
|
if (testWriteFile.exists()) { |
|
|
|
|
|
|
|
testWriteFile.delete(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
testWriteFile.createNewFile(); |
|
|
|
|
|
|
|
FileWriter writer = new FileWriter(testWriteFile); |
|
|
|
|
|
|
|
writer.write(1); |
|
|
|
|
|
|
|
writer.close(); |
|
|
|
|
|
|
|
canWrite = true; |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
e.printStackTrace(); |
|
|
|
|
|
|
|
canWrite = false; |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (testWriteFile != null && testWriteFile.exists()) { |
|
|
|
|
|
|
|
testWriteFile.delete(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
e.printStackTrace(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return canWrite; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Raturns all available SD-Cards in the system (include emulated) Warning: Hack! Based on Android source code of version 4.3 |
|
|
|
|
|
|
|
* (API 18) Because there is no standard way to get it. TODO: Test on future Android versions 4.2+ |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return paths to all available SD-Cards in the system (include emulated) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static List<String> getStorageDirectories() { |
|
|
|
|
|
|
|
// Final set of paths
|
|
|
|
|
|
|
|
final List<String> rv = new ArrayList<>(); |
|
|
|
|
|
|
|
// Primary physical SD-CARD (not emulated)
|
|
|
|
|
|
|
|
final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE"); |
|
|
|
|
|
|
|
// All Secondary SD-CARDs (all exclude primary) separated by ":"
|
|
|
|
|
|
|
|
final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE"); |
|
|
|
|
|
|
|
// Primary emulated SD-CARD
|
|
|
|
|
|
|
|
final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET"); |
|
|
|
|
|
|
|
if (TextUtils.isEmpty(rawEmulatedStorageTarget)) { |
|
|
|
|
|
|
|
// Device has physical external storage; use plain paths.
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(rawExternalStorage)) { |
|
|
|
|
|
|
|
// EXTERNAL_STORAGE undefined; falling back to default.
|
|
|
|
|
|
|
|
rv.add("/storage/sdcard0"); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
rv.add(rawExternalStorage); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Device has emulated storage; external storage paths should have
|
|
|
|
|
|
|
|
// userId burned into them.
|
|
|
|
|
|
|
|
final String rawUserId; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
|
|
|
|
|
|
|
final String path = Environment.getExternalStorageDirectory().getAbsolutePath(); |
|
|
|
|
|
|
|
final String[] folders = DIR_SEPORATOR.split(path); |
|
|
|
|
|
|
|
final String lastFolder = folders[folders.length - 1]; |
|
|
|
|
|
|
|
boolean isDigit = false; |
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(lastFolder) && TextUtils.isDigitsOnly(lastFolder)) { |
|
|
|
|
|
|
|
isDigit = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
rawUserId = isDigit ? lastFolder : ""; |
|
|
|
|
|
|
|
//} else {
|
|
|
|
|
|
|
|
// rawUserId = "";
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
// /storage/emulated/0[1,2,...]
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(rawUserId)) { |
|
|
|
|
|
|
|
rv.add(rawExternalStorage); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
rv.add(rawEmulatedStorageTarget + File.separator + rawUserId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Add all secondary storages
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) { |
|
|
|
|
|
|
|
// All Secondary SD-CARDs splited into array
|
|
|
|
|
|
|
|
final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator); |
|
|
|
|
|
|
|
Collections.addAll(rv, rawSecondaryStorages); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// checkout SD-CARDs writable
|
|
|
|
|
|
|
|
for (int i = rv.size() - 1; i >= 0; i--) { |
|
|
|
|
|
|
|
String path = rv.get(i); |
|
|
|
|
|
|
|
File root = new File(path); |
|
|
|
|
|
|
|
if (!root.exists() || !root.isDirectory() || !canWrite(path)) { |
|
|
|
|
|
|
|
rv.remove(i); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return rv; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Scan the /proc/mounts file and look for lines like this: /dev/block/vold/179:1 /mnt/sdcard vfat |
|
|
|
|
|
|
|
* rw,dirsync,nosuid,nodev,noexec ,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020, |
|
|
|
|
|
|
|
* codepage=cp437,iocharset= iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 When one is found, split it into its |
|
|
|
|
|
|
|
* elements and then pull out the path to the that mount point and add it to the arraylist |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static List<String> readMountsFile() { |
|
|
|
|
|
|
|
// some mount files don't list the default
|
|
|
|
|
|
|
|
// path first, so we add it here to
|
|
|
|
|
|
|
|
// ensure that it is first in our list
|
|
|
|
|
|
|
|
List<String> mounts = new ArrayList<>(); |
|
|
|
|
|
|
|
mounts.add(EXTERNAL_STORAGE_PATH); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
Scanner scanner = new Scanner(new File("/proc/mounts")); |
|
|
|
|
|
|
|
while (scanner.hasNext()) { |
|
|
|
|
|
|
|
String line = scanner.nextLine(); |
|
|
|
|
|
|
|
if (line.startsWith("/dev/block/vold/") || line.startsWith("/dev/block//vold/")) {//
|
|
|
|
|
|
|
|
String[] lineElements = line.split(" "); |
|
|
|
|
|
|
|
// String partition = lineElements[0];
|
|
|
|
|
|
|
|
String element = lineElements[1]; |
|
|
|
|
|
|
|
// don't add the default mount path
|
|
|
|
|
|
|
|
// it's already in the list.
|
|
|
|
|
|
|
|
if (!element.equals(EXTERNAL_STORAGE_PATH)) { |
|
|
|
|
|
|
|
mounts.add(element); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
scanner.close(); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
// e.printStackTrace();
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return mounts; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static List<String> readVoldFile() { |
|
|
|
|
|
|
|
// read /etc/vold.conf or /etc/vold.fstab (it depends on version what
|
|
|
|
|
|
|
|
// config file is present)
|
|
|
|
|
|
|
|
List<String> vold = null; |
|
|
|
|
|
|
|
Scanner scanner = null; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
scanner = new Scanner(new File("/system/etc/vold.fstab")); |
|
|
|
|
|
|
|
} catch (FileNotFoundException e1) { |
|
|
|
|
|
|
|
// e1.printStackTrace();
|
|
|
|
|
|
|
|
scanner = new Scanner(new File("/system/etc/vold.conf")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
vold = new ArrayList<String>(); |
|
|
|
|
|
|
|
vold.add(EXTERNAL_STORAGE_PATH); |
|
|
|
|
|
|
|
while (scanner.hasNext()) { |
|
|
|
|
|
|
|
String line = scanner.nextLine(); |
|
|
|
|
|
|
|
if (TextUtils.isEmpty(line)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
line = line.trim(); |
|
|
|
|
|
|
|
if (line.startsWith("dev_mount")) { |
|
|
|
|
|
|
|
String[] lineElements = line.split(" "); |
|
|
|
|
|
|
|
if (lineElements.length < 3) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String element = lineElements[2]; |
|
|
|
|
|
|
|
if (element.contains(":")) { |
|
|
|
|
|
|
|
element = element.substring(0, element.indexOf(":")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// ignore default path
|
|
|
|
|
|
|
|
if (!element.equals(EXTERNAL_STORAGE_PATH)) { |
|
|
|
|
|
|
|
vold.add(element); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (line.startsWith("mount_point")) { |
|
|
|
|
|
|
|
String element = line.replaceAll("mount_point", "").trim(); |
|
|
|
|
|
|
|
if (!element.equals(EXTERNAL_STORAGE_PATH)) { |
|
|
|
|
|
|
|
vold.add(element); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
// e.printStackTrace();
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return vold; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static List<String> compareMountsWithVold(List<String> mounts, List<String> volds) { |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* 有时候这两个list中的数据并不相同,我们只需要取两个list的交集部分。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
for (int i = mounts.size() - 1; i >= 0; i--) { |
|
|
|
|
|
|
|
String mount = mounts.get(i); |
|
|
|
|
|
|
|
File root = new File(mount); |
|
|
|
|
|
|
|
// 判断目录是否存在并且可读
|
|
|
|
|
|
|
|
if (!root.exists() || !root.isDirectory() || !root.canWrite()) { |
|
|
|
|
|
|
|
mounts.remove(i); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (volds != null && !volds.contains(mount)) { |
|
|
|
|
|
|
|
mounts.remove(i); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 清除无用数据
|
|
|
|
|
|
|
|
if (volds != null) { |
|
|
|
|
|
|
|
volds.clear(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return mounts; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static long getTotalMemory() { |
|
|
|
|
|
|
|
String file_path = "/proc/meminfo";// 系统内存信息文件
|
|
|
|
|
|
|
|
String ram_info; |
|
|
|
|
|
|
|
String[] arrayOfRam; |
|
|
|
|
|
|
|
long initial_memory = 0L; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
FileReader fr = new FileReader(file_path); |
|
|
|
|
|
|
|
BufferedReader localBufferedReader = new BufferedReader(fr, 8192); |
|
|
|
|
|
|
|
// 读取meminfo第一行,系统总内存大小
|
|
|
|
|
|
|
|
ram_info = localBufferedReader.readLine(); |
|
|
|
|
|
|
|
arrayOfRam = ram_info.split("\\s+");// 实现多个空格切割的效果
|
|
|
|
|
|
|
|
initial_memory = |
|
|
|
|
|
|
|
Integer.valueOf(arrayOfRam[1]) * 1024;// 获得系统总内存,单位是KB,乘以1024转换为Byte
|
|
|
|
|
|
|
|
localBufferedReader.close(); |
|
|
|
|
|
|
|
} catch (IOException e) { |
|
|
|
|
|
|
|
e.printStackTrace(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return initial_memory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static long getAvailMemory(Context context) { |
|
|
|
|
|
|
|
ActivityManager activityManager = |
|
|
|
|
|
|
|
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
|
|
|
|
|
|
|
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); |
|
|
|
|
|
|
|
activityManager.getMemoryInfo(memoryInfo); |
|
|
|
|
|
|
|
return memoryInfo.availMem; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|