我目前正在开发一个应用程序,其中显示有关其安装设备的各种不同统计信息。使用其中一个统计数据/ SD卡的总空间。我得到了Here和Here找到的答案。
无论如何,我相信,没有root权限,它就不会返回内部(模拟)SD卡的“真实”值。这是一些代码:
我如何检索Sd位置和尺寸:
new StorageUtils();
ArrayList<StorageInfo> storageInfoList = StorageUtils.getStorageList();
if (storageInfoList.size() > 0) {
tvStorageAName = (TextView) findViewById(R.id.tvStorageAName);
tvStorageAName.setText(storageInfoList.get(0).path);
devStorageA = StorageUtils.getReadableFileSize(
(StorageUtils.getUsedSpace(storageInfoList.get(0).path)),
true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(storageInfoList.get(0).path)), true);
if (storageInfoList.size() > 1) {
tvStorageBName = (TextView) findViewById(R.id.tvStorageBName);
tvStorageBName.setText(storageInfoList.get(1).path);
devStorageB = StorageUtils.getReadableFileSize(
StorageUtils.getUsedSpace(storageInfoList.get(1).path)
+ (StorageUtils.getUsedSpace("system/")), true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(storageInfoList.get(1).path)),
true);
} else {
devStorageB = "N/A";
}
} else {
devStorageA = "N/A";
devStorageB = "N/A";
}
我的StorageUtils类:
public class StorageUtils {
private static final String TAG = "StorageUtils";
public static class StorageInfo {
public final String path;
public final boolean internal;
public final boolean readonly;
public final int display_number;
StorageInfo(String path, boolean internal, boolean readonly,
int display_number) {
this.path = path;
this.internal = internal;
this.readonly = readonly;
this.display_number = display_number;
}
}
public static ArrayList<StorageInfo> getStorageList() {
ArrayList<StorageInfo> list = new ArrayList<StorageInfo>();
String def_path = Environment.getExternalStorageDirectory().getPath();
boolean def_path_internal = !Environment.isExternalStorageRemovable();
String def_path_state = Environment.getExternalStorageState();
boolean def_path_available = def_path_state
.equals(Environment.MEDIA_MOUNTED)
|| def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
boolean def_path_readonly = Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
BufferedReader buf_reader = null;
try {
HashSet<String> paths = new HashSet<String>();
buf_reader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
int cur_display_number = 1;
Log.d(TAG, "/proc/mounts");
while ((line = buf_reader.readLine()) != null) {
Log.d(TAG, line);
if (line.contains("vfat") || line.contains("/mnt")) {
StringTokenizer tokens = new StringTokenizer(line, " ");
String unused = tokens.nextToken(); // device
String mount_point = tokens.nextToken(); // mount point
if (paths.contains(mount_point)) {
continue;
}
unused = tokens.nextToken(); // file system
List<String> flags = Arrays.asList(tokens.nextToken()
.split(",")); // flags
boolean readonly = flags.contains("ro");
if (mount_point.equals(def_path)) {
paths.add(def_path);
list.add(new StorageInfo(def_path, def_path_internal,
readonly, -1));
} else if (line.contains("/dev/block/vold")) {
if (!line.contains("/mnt/secure")
&& !line.contains("/mnt/asec")
&& !line.contains("/mnt/obb")
&& !line.contains("/dev/mapper")
&& !line.contains("tmpfs")) {
paths.add(mount_point);
list.add(new StorageInfo(mount_point, false,
readonly, cur_display_number++));
}
}
}
}
if (!paths.contains(def_path) && def_path_available) {
list.add(new StorageInfo(def_path, def_path_internal,
def_path_readonly, -1));
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (buf_reader != null) {
try {
buf_reader.close();
} catch (IOException ex) {
}
}
}
return list;
}
public static String getReadableFileSize(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit)
return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1)
+ (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
@SuppressLint("NewApi")
public static long getFreeSpace(String path) {
StatFs statFs = new StatFs(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
long sdAvailSize = statFs.getFreeBlocksLong()
* statFs.getBlockSizeLong();
return sdAvailSize;
} else {
@SuppressWarnings("deprecation")
double sdAvailSize = (double) statFs.getFreeBlocks()
* (double) statFs.getBlockSize();
return (long) sdAvailSize;
}
}
public static long getUsedSpace(String path) {
return getTotalSpace(path) - getFreeSpace(path);
}
@SuppressLint("NewApi")
public static long getTotalSpace(String path) {
StatFs statFs = new StatFs(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
long sdTotalSize = statFs.getBlockCountLong()
* statFs.getBlockSizeLong();
return sdTotalSize;
} else {
@SuppressWarnings("deprecation")
double sdTotalSize = (double) statFs.getBlockCount()
* statFs.getBlockSize();
return (long) sdTotalSize;
}
}
}
问题是我猜,这是获取这些大小的最准确方法(没有root权限),还是有更好的方法来做到这一点?非常感谢任何和所有帮助,感谢您花时间阅读本文!
编辑:外部SD卡根本没有给我带来任何问题。内部SD卡(也似乎是数据/目录)未显示总计。它在我的测试设备上缺少~5Gb。有什么想法吗?
EDIT2:我的手机上有一个朋友测试,内部显示36.0 GB(已使用)/ 8.6 GB(总计),为什么会返回这样的零星结果?应用程序怎么样,比如说文件管理器返回结果?
答案 0 :(得分:0)
经过一段时间的修补,我发现了我的满意。
在我的片段中:
ArrayList<StorageInfo> storageInfoList = StorageUtils.getStorageList();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
kitKatWorkaround();
} else if (storageInfoList.size() > 0) {
tvStorageAName.setText(storageInfoList.get(0).path);
long usedA = StorageUtils.getUsedSpace(storageInfoList.get(0).path);
long totalA = StorageUtils
.getTotalSpace(storageInfoList.get(0).path);
devStorageA = StorageUtils.getReadableFileSize(usedA, true) + "/"
+ StorageUtils.getReadableFileSize(totalA, true);
progA.setProgress(0);
progA.setProgress(Integer.parseInt(StorageUtils.getReadableFileSize(usedA, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "")));
progA.setMax(Integer.parseInt(StorageUtils.getReadableFileSize(totalA, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "")));
Log.d("Storage", usedA + "/" + totalA);
if (storageInfoList.size() > 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
&& !storageInfoList.get(0).internal) {
kitKatWorkaround();
}
tvStorageBName.setText(storageInfoList.get(1).path);
long usedB = StorageUtils
.getUsedSpace(storageInfoList.get(1).path)
+ (StorageUtils.getUsedSpace("system/"));
long totalB = StorageUtils
.getTotalSpace(storageInfoList.get(1).path);
devStorageB = StorageUtils.getReadableFileSize(usedB, true)
+ "/" + StorageUtils.getReadableFileSize(totalB, true);
progB.setProgress(0);
progB.setProgress(Integer.parseInt(StorageUtils.getReadableFileSize(usedB, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "").trim()));
progB.setMax(Integer.parseInt(StorageUtils.getReadableFileSize(totalB, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "").trim()));
Log.d("Storage", usedB + "/" + totalB);
} else {
tvStorageBName.setVisibility(View.GONE);
tvStorageB.setVisibility(View.GONE);
progB.setVisibility(View.GONE);
devStorageB = "N/A";
}
} else {
devStorageA = "N/A";
tvStorageBName.setVisibility(View.GONE);
tvStorageB.setVisibility(View.GONE);
progB.setVisibility(View.GONE);
devStorageB = "N/A";
}
//
// #################################
// STORAGE
tvStorageA.setText(devStorageA);
tvStorageB.setText(devStorageB);
//
// #################################
}
并修订了StorageUtils方法:
public static String getReadableFileSize(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit)
return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1)
+ (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
@SuppressLint("NewApi")
public static long getFreeSpace(String path) {
StatFs statFs = new StatFs(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
long sdAvailSize = statFs.getFreeBlocksLong()
* statFs.getBlockSizeLong();
return sdAvailSize;
} else {
@SuppressWarnings("deprecation")
double sdAvailSize = (double) statFs.getFreeBlocks()
* (double) statFs.getBlockSize();
return (long) sdAvailSize;
}
}
public static long getUsedSpace(String path) {
return getTotalSpace(path) - getFreeSpace(path);
}
@SuppressLint("NewApi")
public static long getTotalSpace(String path) {
StatFs statFs = new StatFs(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
long sdTotalSize = statFs.getBlockCountLong()
* statFs.getBlockSizeLong();
return sdTotalSize;
} else {
@SuppressWarnings("deprecation")
double sdTotalSize = (double) statFs.getBlockCount()
* statFs.getBlockSize();
return (long) sdTotalSize;
}
}
修改强> 对于那些正在寻找的人来说,还有KitKatWorkaround方法:
@SuppressLint("NewApi")
public void kitKatWorkaround() {
File[] sdCards = getActivity().getApplicationContext()
.getExternalCacheDirs();
if (sdCards.length > 0
&& sdCards[0] != null
&& Environment.getStorageState(sdCards[0]).equals(
Environment.MEDIA_MOUNTED)) {
File sdCard1 = sdCards[0];
tvStorageAName.setText(sdCard1.getAbsolutePath()
.replace(
"Android/data/" + getActivity().getPackageName()
+ "/cache", ""));
long usedA = StorageUtils.getUsedSpace(sdCard1.getAbsolutePath());
long totalA = StorageUtils.getTotalSpace(sdCard1.getAbsolutePath());
devStorageA = StorageUtils.getReadableFileSize(usedA, true) + "/"
+ StorageUtils.getReadableFileSize(totalA, true);
progA.setProgress(0);
progA.setProgress(Integer.parseInt(StorageUtils.getReadableFileSize(usedA, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "").trim()));
progA.setMax(Integer.parseInt(StorageUtils.getReadableFileSize(totalA, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "").trim()));
Log.d("Storage", usedA + "/" + totalA);
} else {
devStorageA = "N/A";
}
if (sdCards.length > 1
&& sdCards[1] != null
&& Environment.getStorageState(sdCards[1]).equals(
Environment.MEDIA_MOUNTED)) {
File sdCard2 = sdCards[1];
tvStorageBName.setText(sdCard2.getAbsolutePath()
.replace(
"Android/data/" + getActivity().getPackageName()
+ "/cache", ""));
long usedB = StorageUtils.getUsedSpace(sdCard2.getAbsolutePath());
long totalB = StorageUtils.getTotalSpace(sdCard2.getAbsolutePath());
devStorageB = StorageUtils.getReadableFileSize(usedB, true) + "/"
+ StorageUtils.getReadableFileSize(totalB, true);
progB.setProgress(0);
progB.setProgress(Integer.parseInt(StorageUtils.getReadableFileSize(totalB, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "").trim()));
progB.setMax(Integer.parseInt(StorageUtils.getReadableFileSize(totalB, true).replace(".", "").replace("k", "").replace("M", "").replace("G", "").replace("T", "").replace("P", "").replace("B", "").trim()));
Log.d("Storage", usedB + "/" + totalB);
} else {
tvStorageBName.setVisibility(View.GONE);
tvStorageB.setVisibility(View.GONE);
progB.setVisibility(View.GONE);
devStorageB = "N/A";
}
tvStorageA.setText(devStorageA);
tvStorageB.setText(devStorageB);
}