Android内部SD卡大小不返回“true”大小

时间:2014-01-23 04:05:26

标签: android android-sdcard

我目前正在开发一个应用程序,其中显示有关其安装设备的各种不同统计信息。使用其中一个统计数据/ SD卡的总空间。我得到了HereHere找到的答案。

无论如何,我相信,没有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(总计),为什么会返回这样的零星结果?应用程序怎么样,比如说文件管理器返回结果?

1 个答案:

答案 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);
}