android 设备存储信息
• **Filesystem**:文件系统的名称。
• **Size**:文件系统的总大小。
• **Used**:已经使用的空间。
• **Avail**:可用的空间。
• **Use%** :已经使用的百分比。
• **Mounted on**:文件系统挂载的挂载点。
Filesystem Size Used Avail Use% Mounted on
/dev/root 2.9G 1.2G 1.6G 45% /
文件系统的名称:
文件系统的名称表示每个分区或设备在系统中的标识。以下是详细解释:
• /dev/root:表示根文件系统,通常存储操作系统的核心文件和目录。
文件挂载点:
文件挂载点表示文件系统在操作系统中访问的位置。以下是每个挂载点的详细解释:
• / :根目录,是整个文件系统的起点,所有其他目录都在这个目录下。
根目录 / 不是就代表所有的存储吗?
Filesystem Size Used Avail Use% Mounted on
/dev/root 2.9G 1.2G 1.6G 45% /
- 解释根目录的存储大小:
虽然根目录 (/) 是整个文件系统的起点,但它并不代表设备上所有的存储大小。根目录包含了操作系统的核心文件和目录,
但设备上的其他分区,如 /data、/cache 和 /vendor 等, 虽然在逻辑上是根目录的一部分, 但在物理存储上是独立的分区。每个分区都有自己的存储大小和用途。
- 详细解释各分区的关系:
• 根目录 (/) :包含操作系统的基本文件和目录,如 /bin、/etc、/lib 等,但并不包括其他挂载点的数据。
• 其他分区:/data、/cache、/vendor 等分区独立存在,并挂载在根目录下的不同路径。这些分区用于特定的目的,例如存储用户数据、缓存数据和供应商文件。
- 根目录与其他分区的区别:
• 根目录 (/) 的大小:2.9G,其中 1.2G 已使用,1.6G 可用。它只包括操作系统的基本文件和目录。
• 其他分区:它们的大小各不相同,例如 /data 分区有 10G,其中 3.1G 已使用,6.5G 可用。这些分区用于特定的存储目的。
结论:
根目录 (/)是文件系统的起点,它的存储大小只包括挂载点的大小,
每个分区有其独立的存储大小,并挂载在根目录的不同路径上。
设备的总存储空间是这些分区的总和,而不是根目录的大小。
为什么不同的路径进入可以到达同样的文件?怎么判断是否是同一个文件?
/storage/emulated/0
/mnt/runtime/default/emulated/0/
/sdcard/
k62v1_64_bsp:/storage/emulated/0 # df -h /storage/emulated/0/
Filesystem Size Used Avail Use% Mounted on
/data/media 10G 3.2G 6.5G 33% /mnt/runtime/write/emulated
k62v1_64_bsp:/storage/emulated/0 # df -h /mnt/runtime/default/emulated/0/
Filesystem Size Used Avail Use% Mounted on
/data/media 10G 3.2G 6.5G 33% /mnt/runtime/write/emulated
k62v1_64_bsp:/storage/emulated/0 # df -h /sdcard/
Filesystem Size Used Avail Use% Mounted on
/data/media 10G 3.1G 6.5G 33% /mnt/runtime/write/emulated
方法 1:
使用 File.getCanonicalPath() 方法可以判断两个路径是否指向同一个文件或目录。
// 定义需要比较的路径
// File file1 = new File("/storage/emulated/0");
// File file2 = new File("/mnt/runtime/default/emulated/0");//new StatFs(path2);//出现这个错误的原因是路径 /mnt/runtime/default/emulated/0 可能需要特殊权限才能访问
// File file3 = new File("/sdcard");
// f1 and f2 different
// f1 and f3 the same
// f2 and f3 the different
File file1 = new File("/storage/emulated/0/DCIM");
File file2 = new File("/mnt/runtime/default/emulated/0/DCIM");
File file3 = new File("/sdcard/DCIM");
// f1 and f2 different
// f1 and f3 the same
// f2 and f3 the different
// 获取规范路径
String canonicalPath1 = file1.getCanonicalPath();
String canonicalPath2 = file2.getCanonicalPath();
String canonicalPath3 = file3.getCanonicalPath();
// 比较规范路径
boolean isSameFile1And2 = canonicalPath1.equals(canonicalPath2);
boolean isSameFile1And3 = canonicalPath1.equals(canonicalPath3);
boolean isSameFile2And3 = canonicalPath2.equals(canonicalPath3);
方法 2:比较文件系统信息:
使用 StatFs 类获取路径的文件系统信息,包括块大小、块总数和可用块数等。
块大小、块总数和可用块数是否相同。
不推荐。
StatFs stat2 = new StatFs(path2);//出现这个错误的原因是路径 /mnt/runtime/default/emulated/0 可能需要特殊权限才能访问
// Caused by: java.lang.IllegalArgumentException: Invalid path: /mnt/runtime/default/emulated/0
// Caused by: android.system.ErrnoException: statvfs failed: EACCES (Permission denied)
// at libcore.io.Linux.statvfs(Native Method)
// 比较文件系统信息
val isSameFileSystem = (stat1.blockSizeLong == stat2.blockSizeLong
&& stat1.blockSizeLong == stat3.blockSizeLong
&& stat1.blockCountLong == stat2.blockCountLong
&& stat1.blockCountLong == stat3.blockCountLong
&& stat1.availableBlocksLong == stat2.availableBlocksLong
&& stat1.availableBlocksLong == stat3.availableBlocksLong)
结论:不同位置访问同一个文件
1. 符号链接 /sdcard 可以是 /storage/emulated/0 的符号链接。
2. 挂载点的重定向
Android系统中的 /storage/emulated/0、/mnt/runtime/default/emulated/0 和 /sdcard 都指向同一个物理存储位置 /data/media/0。这通过系统的挂载点重定向机制实现,使得这些路径可以访问相同的数据。
3. 目的: 兼容性和方便性
判断方法:
推荐>>> 方法一:使用 getCanonicalPath() 方法比较规范路径 是否是同一个文件,简单,避免权限问题.
方法二:使用 StatFs 类比较文件系统信息,,,权限问题!,适用于,信息统计。
// 定义需要比较的路径
// File file1 = new File("/storage/emulated/0");
// File file2 = new File("/mnt/runtime/default/emulated/0");//如果使用 StatFnew StatFs(path2);判断,会出现这个错误的原因是路径 /mnt/runtime/default/emulated/0 可能需要特殊权限才能访问
// File file3 = new File("/sdcard");
// f1 and f2 different
// f1 and f3 the same
// f2 and f3 the different
//判断,子文件。
File file1 = new File("/storage/emulated/0/DCIM");
File file2 = new File("/mnt/runtime/default/emulated/0/DCIM");//特殊情况 ,权限。。。虚拟路径,用于多用户环境和权限控制
File file3 = new File("/sdcard/DCIM");
// f1 and f2 different
// f1 and f3 the same
// f2 and f3 the different
Log.i(TAG, "compareIsSamePath: path1:"+file1.getPath());// /storage/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath: path2:"+file2.getPath());// /mnt/runtime/default/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath: path3:"+file3.getPath());// /sdcard/DCIM
// 获取规范路径
String canonicalPath1 = file1.getCanonicalPath();
String canonicalPath2 = file2.getCanonicalPath();
String canonicalPath3 = file3.getCanonicalPath();
Log.i(TAG, "compareIsSamePath1: "+canonicalPath1);// /storage/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath2: "+canonicalPath2);// /mnt/runtime/default/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath3: "+canonicalPath3);// /storage/emulated/0/DCIM <----- /sdcard/DCIMTODO 改变了。ok
/*
* /storage/emulated/0 -> /data/media/0
* /sdcard -> /storage/emulated/0
*
* sdcardfs 文件系统: /mnt/runtime/default/emulated/0 是使用 sdcardfs 文件系统虚拟化的路径,这个路径提供了对原始路径的多用户隔离和权限控制。
* */
// 比较规范路径
boolean isSameFile1And2 = canonicalPath1.equals(canonicalPath2);
boolean isSameFile1And3 = canonicalPath1.equals(canonicalPath3);
boolean isSameFile2And3 = canonicalPath2.equals(canonicalPath3);
怎么统计磁盘的总大小?
1个挂载点只能
如何判断 2 个分区是否,共享存储?
Filesystem 1K-blocks Used Available Use% Mounted on
tmpfs 945912 1420 944492 1% /dev
tmpfs 945912 0 945912 0% /mnt
...
/dev/block/dm-2 10182948 3155920 7027028 31% /data
/data/media 10182948 3155920 7027028 31% /mnt/runtime/default/emulated
tmpfs 是一种基于内存的文件系统,通常用于存储临时文件。它的特点是数据存储在内存中,而不是物理存储设备上,因此读写速度非常快。
使用场景:
tmpfs 文件系统在 Linux 和 Android 系统中广泛用于存储临时文件,例如设备上的 /dev
和 /mnt
目录。它们用于存储设备文件和挂载点的信息。
tmpfs的存储空间和区域:2块不同。
tmpfs 945912 1420 944492 1% /dev
tmpfs 945912 0 945912 0% /mnt
下面这 2 个是否一样呢?
/dev/block/dm-2 10182948 3155920 7027028 31% /data
/data/media 10182948 3155920 7027028 31% /mnt/runtime/default/emulated
- 大小相同,使用相同,怎么确定是否是同一块?
方法 1。 查看物理地址。没法查看。。。。不知道咋搞
方法 2。 分析挂载信息。
cat /proc/mounts 查看所有的挂载信息: 找到相关信息:
130|k62v1_64_bsp:/ # cat /proc/mounts | grep /data
/dev/block/dm-2 /data ext4 rw,seclabel,nosuid,nodev,noatime,noauto_da_alloc,resuid=10010,resgid=1065,errors=panic,data=ordered 0 0
...
k62v1_64_bsp:/ # cat /proc/mounts | grep /mnt/runtime/default/emulated
/data/media /mnt/runtime/default/emulated sdcardfs rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,multiuser,mask=6,derive_gid,default_normal 0 0
...
分析,字段解释:
- /dev/block/dm-2:设备文件,表示逻辑卷或分区。
- /data:挂载点目录。
- ext4:文件系统类型。<-------------重点。
- rw:读写权限,表示挂载为可读写。
- seclabel:启用了安全标签。
- nosuid:不允许设置用户ID或组ID。
- nodev:不解释设备文件。
- noatime:不更新访问时间。
- noauto_da_alloc:不自动分配磁盘块。
- resuid=10010:保留块的所有者用户ID。
- resgid=1065:保留块的所有者组ID。
- errors=panic:文件系统错误时内核会触发panic。
- data=ordered:文件系统元数据写入顺序,保证数据写入前元数据写入。
/mnt/runtime/default/emulated
字段解释:
- /data/media:源目录。<-------------重点。
- /mnt/runtime/default/emulated:目标挂载点目录。
- sdcardfs:文件系统类型,Android上的一种虚拟文件系统,通常用于实现多用户的存储隔离。<-------------重点。
- rw:读写权限,表示挂载为可读写。
- nosuid:不允许设置用户ID或组ID。
- nodev:不解释设备文件。
- noexec:不允许执行文件。
- noatime:不更新访问时间。
- fsuid=1023:文件系统的用户ID。
- fsgid=1023:文件系统的组ID。
- gid=1015:使用的组ID。
- multiuser:支持多用户。
- mask=6:掩码,控制文件和目录的权限。
- derive_gid:派生组ID。
- default_normal:默认挂载选项。
结论:
- /mnt/runtime/default/emulated 是 共享 /data 存储的。
原因:
/data
存储分区,挂载在物理设备/dev/block/dm-2
上,使用的是ext4
文件系统
ext4 真实的存储系统。
/mnt/runtime/default/emulated
基于sdcardfs
虚拟文件系统
。/mnt/runtime/default/emulated
的源目录是/data/media
,是/data
的子目录。而/data
挂载在/dev/block/dm-2
上 挂载出来。
提供了一个虚拟视图,通常用于多用户环境,具有特定的安全和访问控制选项。
所以:
/mnt/runtime/default/emulated sdcardfs
提供虚拟化访问 /data/media
,但底层数据仍由 ext4
文件系统管理。
存储空间分类
。。。后续补充。。。 /storage/emulated/0/Android/data/包名
内部存储**
Context的getFileStreamPath、getFilesDir
外部存储**
Environment类的getExternalStoragePublicDirectory::
/storage/emulated/0/
/storage/emulated/userid (如果设备支持多用户的话userid是当前的用户id,一般情况下是0)
app专有目录 /storage/emulated/userid/Android/data/packageName (packageName是app的包名)、 /storage/emulated/userid/Android/obb/packageName
通过Context类的getExternalXXX等方法,可以把文件存放在app专有目录
其他目录。
除了app专有目录外,剩下的这些目录它们都是可以被任何进程访问的(在获取对应权限后),这些目录的uid都是root,gid都是everybody。下图显示了一些目录。
代码:
public class StorageUtil {
private static final String TAG = "StorageUtil";
/**
* 检查所有挂载点的存储空间并打印日志
*/
public static void checkAllStorage() {
// 获取所有挂载点
Map<String, String> mountPoints = getMountPoints();
long totalSpace = 0;
long totalUsed = 0;
Set<StorageInfo> setStorage = new HashSet<>();
for (Map.Entry<String, String> entry : mountPoints.entrySet()) {
StorageInfo storageInfo = getStorageInfo(entry.getKey());
if (storageInfo != null) {
if (storageInfo.totalSpace<1){// 0 的忽略
continue;
}
if (setStorage.contains(storageInfo)
//特殊忽略,,,有时判断,,大小会失误。
// Filesystem 1K-blocks Used Available Use% Mounted on
// /dev/block/dm-2 10182948 3106668 7076280 31% /data
// /data/media 10182948 3106668 7076280 31% /mnt/runtime/default/emulated 忽略这个。防止重复计算
||("/data/media".equals(entry.getValue()) && mountPoints.containsKey("/data"))){
Log.e(TAG, " 重复,需要忽略的:设备节点:" + entry.getValue()
+",挂载点: " + entry.getKey()
+",总存储空间: " + formatSize(storageInfo.totalSpace)
+",已使用存储空间: " + formatSize(storageInfo.usedSpace)
+",可用存储空间: " + formatSize(storageInfo.availableSpace)
+"已使用百分比: " + storageInfo.usedPercentage + "%");
}else {
totalSpace += storageInfo.totalSpace;
totalUsed += storageInfo.usedSpace;
setStorage.add(storageInfo);
Log.i(TAG, "设备节点:" + entry.getValue()
+",挂载点: " + entry.getKey()
+",总存储空间: " + formatSize(storageInfo.totalSpace)
+",已使用存储空间: " + formatSize(storageInfo.usedSpace)
+",可用存储空间: " + formatSize(storageInfo.availableSpace)
+"已使用百分比: " + storageInfo.usedPercentage + "%");
}
}
}
// 打印总存储空间的日志
Log.i(TAG, "总存储空间: " + formatSize(totalSpace)+"--"+totalSpace);
Log.i(TAG, "总已使用存储空间: " + formatSize(totalUsed)+"--"+totalUsed);
Log.i(TAG, "总已使用百分比: " + ((double) totalUsed / totalSpace * 100) + "%");
}
/**
* 获取所有挂载点目录及其对应的设备节点
* @return 挂载点目录和设备节点的映射
* key mount 点,
* value Filesystem
*/
private static Map<String, String> getMountPoints() {
Map<String, String> mountPoints = new HashMap<>();
//不合适。修改,适配下面
// Filesystem Size Used Avail Use% Mounted on
// tmpfs 924M 1.3M 922M 1% /dev
// tmpfs 924M 0 924M 0% /mnt
//这两个目录虽然都使用了 tmpfs 文件系统,并且显示的总容量相同,但它们是 独立的存储区域。这意味着它们各自有自己的内存分配,并不是共享同一块内存空间。
try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
String line;
while ((line = br.readLine()) != null) {
String[] fields = line.split(" ");
if (fields.length > 1) {
String device = fields[0];
String mountPoint = fields[1];//挂载点。
File dir = new File(mountPoint);
if (dir.exists() && dir.isDirectory()) {
mountPoints.put(mountPoint,device);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return mountPoints;
}
/**
* 获取指定挂载点的存储信息
* @param path 挂载点路径
* @return 存储信息对象
*/
private static StorageInfo getStorageInfo(String path) {
if (TextUtils.isEmpty(path))return null;
File dir = new File(path);
if (dir != null && dir.exists() && dir.isDirectory()) {
StatFs stat = new StatFs(dir.getPath());
long blockSize = stat.getBlockSizeLong();
long totalBlocks = stat.getBlockCountLong();
long availableBlocks = stat.getAvailableBlocksLong();
long totalSpace = totalBlocks * blockSize;
long availableSpace = availableBlocks * blockSize;
long usedSpace = totalSpace - availableSpace;
double usedPercentage = (double) usedSpace / totalSpace * 100;
return new StorageInfo(totalSpace, availableSpace, usedSpace, usedPercentage);
}
return null;
}
/**
* 检查存储空间占用百分比并显示Toast通知,同时打印日志
* @param context 应用上下文
*/
public static void checkStorage(Context context) {
// 获取外部存储状态
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 获取外部存储的路径
String path = Environment.getExternalStorageDirectory().getPath();///storage/emulated/0
Log.i(TAG, "checkStorage: 存储路径:"+path);
try {
Log.i(TAG, "checkStorage: 存储路径:"+(new File(path).getCanonicalPath()));///storage/emulated/0
} catch (IOException e) {
throw new RuntimeException(e);
}
StatFs stat = new StatFs(path);
// 获取存储块的大小(字节)
long blockSize = stat.getBlockSizeLong();
// 获取总的存储块数量
long totalBlocks = stat.getBlockCountLong();
// 获取可用的存储块数量
long availableBlocks = stat.getAvailableBlocksLong();
// 计算总存储空间和可用存储空间
long totalStorage = totalBlocks * blockSize;
long availableStorage = availableBlocks * blockSize;
// 计算已使用的存储空间
long usedStorage = totalStorage - availableStorage;
double usedPercentage = (double) usedStorage / totalStorage * 100;
// 打印日志
Log.i(TAG, "总存储空间: " + formatSize(totalStorage));
Log.i(TAG, "已使用存储空间: " + formatSize(usedStorage));
Log.i(TAG, "可用存储空间: " + formatSize(availableStorage));
Log.i(TAG, "已使用百分比: " + usedPercentage + "%");
// 检查是否超过80%
if (usedPercentage > 80.0) {
// 显示Toast通知
Toast.makeText(context, "存储空间已超过80%", Toast.LENGTH_LONG).show();
Log.i(TAG, "checkStorage: 存储空间已超过80%");
} else {
Toast.makeText(context, "存储空间正常", Toast.LENGTH_LONG).show();
Log.i(TAG, "checkStorage: 存储空间正常");
}
} else {
Toast.makeText(context, "无法访问外部存储", Toast.LENGTH_LONG).show();
Log.i(TAG, "checkStorage: 无法访问外部存储");
}
}
/**
* 获取存储空间占用百分比
* @return 存储空间占用百分比
*/
public static double getStorageUsagePercentage() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory().getPath();
StatFs stat = new StatFs(path);
long blockSize = stat.getBlockSizeLong();
long totalBlocks = stat.getBlockCountLong();
long availableBlocks = stat.getAvailableBlocksLong();
long totalStorage = totalBlocks * blockSize;
long availableStorage = availableBlocks * blockSize;
long usedStorage = totalStorage - availableStorage;
return (double) usedStorage / totalStorage * 100;
} else {
return -1; // 表示无法访问外部存储
}
}
public static void compareIsSamePath() {
try {
// 定义需要比较的路径
// File file1 = new File("/storage/emulated/0");
// File file2 = new File("/mnt/runtime/default/emulated/0");//如果使用 StatFnew StatFs(path2);判断,会出现这个错误的原因是路径 /mnt/runtime/default/emulated/0 可能需要特殊权限才能访问
// File file3 = new File("/sdcard");
// f1 and f2 different
// f1 and f3 the same
// f2 and f3 the different
//判断,子文件。
File file1 = new File("/storage/emulated/0/DCIM");
File file2 = new File("/mnt/runtime/default/emulated/0/DCIM");//特殊情况 ,权限。。。虚拟路径,用于多用户环境和权限控制
File file3 = new File("/sdcard/DCIM");
// f1 and f2 different
// f1 and f3 the same
// f2 and f3 the different
Log.i(TAG, "compareIsSamePath: path1:"+file1.getPath());// /storage/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath: path2:"+file2.getPath());// /mnt/runtime/default/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath: path3:"+file3.getPath());// /sdcard/DCIM
// 获取规范路径
String canonicalPath1 = file1.getCanonicalPath();
String canonicalPath2 = file2.getCanonicalPath();
String canonicalPath3 = file3.getCanonicalPath();
Log.i(TAG, "compareIsSamePath1: "+canonicalPath1);// /storage/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath2: "+canonicalPath2);// /mnt/runtime/default/emulated/0/DCIM
Log.i(TAG, "compareIsSamePath3: "+canonicalPath3);// /storage/emulated/0/DCIM <----- /sdcard/DCIMTODO 改变了。ok
/*
* /storage/emulated/0 -> /data/media/0
* /sdcard -> /storage/emulated/0
*
* sdcardfs 文件系统: /mnt/runtime/default/emulated/0 是使用 sdcardfs 文件系统虚拟化的路径,这个路径提供了对原始路径的多用户隔离和权限控制。
* */
// 比较规范路径
boolean isSameFile1And2 = canonicalPath1.equals(canonicalPath2);
boolean isSameFile1And3 = canonicalPath1.equals(canonicalPath3);
boolean isSameFile2And3 = canonicalPath2.equals(canonicalPath3);
if (isSameFile1And2) {
System.out.println("/storage/emulated/0 and /mnt/runtime/default/emulated/0 point to the same file or directory.");
} else {
System.out.println("/storage/emulated/0 and /mnt/runtime/default/emulated/0 point to different files or directories.");
}
if (isSameFile1And3) {
System.out.println("/storage/emulated/0 and /sdcard point to the same file or directory.");
} else {
System.out.println("/storage/emulated/0 and /sdcard point to different files or directories.");
}
if (isSameFile2And3) {
System.out.println("/mnt/runtime/default/emulated/0 and /sdcard point to the same file or directory.");
} else {
System.out.println("/mnt/runtime/default/emulated/0 and /sdcard point to different files or directories.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
//一般不这么判断----不推荐
@Deprecated
public static void compareIsSamePath2() {
// 定义需要比较的路径
String path1 = Environment.getExternalStorageDirectory().getPath();
String path2 = "/mnt/runtime/default/emulated/0";
String path3 = "/sdcard";
Log.i(TAG, "compareIsSamePath: path1:"+path1);
Log.i(TAG, "compareIsSamePath: path2:"+path2);
Log.i(TAG, "compareIsSamePath: path3:"+path3);
// 获取文件系统信息
StatFs stat1 = new StatFs(path1);
StatFs stat2 = new StatFs(path2);//出现这个错误的原因是路径 /mnt/runtime/default/emulated/0 可能需要特殊权限才能访问
// Caused by: java.lang.IllegalArgumentException: Invalid path: /mnt/runtime/default/emulated/0
// Caused by: android.system.ErrnoException: statvfs failed: EACCES (Permission denied)
// at libcore.io.Linux.statvfs(Native Method)
StatFs stat3 = new StatFs(path3);
// 比较文件系统信息
boolean isSameFileSystem = (stat1.getBlockSizeLong() == stat2.getBlockSizeLong()
&& stat1.getBlockSizeLong() == stat3.getBlockSizeLong()
&& stat1.getBlockCountLong() == stat2.getBlockCountLong()
&& stat1.getBlockCountLong() == stat3.getBlockCountLong()
&& stat1.getAvailableBlocksLong() == stat2.getAvailableBlocksLong()
&& stat1.getAvailableBlocksLong() == stat3.getAvailableBlocksLong());
if (isSameFileSystem) {
Log.i(TAG, "compareIsSamePath: These paths point to the same file system.");
} else {
Log.e(TAG, "compareIsSamePath: These paths point to different file systems.");
}
}
/**
* 格式化存储大小
* @param size 存储大小(字节)
* @return 格式化后的存储大小字符串
*/
private static String formatSize(long size) {
String suffix = null;
float fSize = size;
if (fSize >= 1024) {
suffix = "KB";
fSize /= 1024;
if (fSize >= 1024) {
suffix = "MB";
fSize /= 1024;
if (fSize >= 1024) {
suffix = "GB";
fSize /= 1024;
}
}
}
StringBuilder resultBuffer = new StringBuilder(Long.toString((long) fSize));
int commaOffset = resultBuffer.length() - 3;
while (commaOffset > 0) {
resultBuffer.insert(commaOffset, ',');
commaOffset -= 3;
}
if (suffix != null) resultBuffer.append(suffix);
return resultBuffer.toString();
}
/**
* 存储信息类
*/
private static class StorageInfo {
long totalSpace;
long availableSpace;
long usedSpace;
double usedPercentage;
StorageInfo(long totalSpace, long availableSpace, long usedSpace, double usedPercentage) {
this.totalSpace = totalSpace;
this.availableSpace = availableSpace;
this.usedSpace = usedSpace;
this.usedPercentage = usedPercentage;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StorageInfo that = (StorageInfo) o;
return totalSpace == that.totalSpace && availableSpace == that.availableSpace && usedSpace == that.usedSpace;
}
@Override
public int hashCode() {
return Objects.hash(totalSpace, availableSpace, usedSpace);
}
@Override
public String toString() {
return "StorageInfo{" +
"totalSpace=" + totalSpace +
", availableSpace=" + availableSpace +
", usedSpace=" + usedSpace +
", usedPercentage=" + usedPercentage +
'}';
}
}
}
参考文章:
牛晓伟 .待测试。 mp.weixin.qq.com/s/6mtFmO1Nh…
通用缓存存储设计方案。。Tecent juejin.cn/post/720770…