11

我有一个预存储在 SD 卡中的大量数据的应用程序。

我们支持所有平板电脑ICS 起。我无法找到在所有设备上正确访问 SDCard 位置的方法。

我查看了这里给出的各种解决方案,但它们似乎并不适用于所有情况。寻找通用解决方案。

即使有人能告诉我所有可能的 SDCard 挂载点。

仅当可以缩小解决方案的范围时,我才针对 android 平板电脑。

4

4 回答 4

15

Unfortunately this is a common problem due to the fact that Android devices are highly fragmented. Environment.getExternalStorageDirectory() refers to whatever the device manufacturer considers to be "external storage". On some devices, this is removable media, like an SD card. On some devices, this is a portion of on-device flash.(http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()) Here, "external storage" means "the drive accessible via USB Mass Storage mode when mounted on a host machine". If a device manufacturer has elected to have external storage be on-board flash and also has an SD card, you will need to contact that manufacturer to determine whether or not you can use the SD card. For most conforming android devices(known ones from google compliance list) the Environment.getExternalStorageDirectory() should work. Or you could write a custom storage class that looks at the mount points and gives you the right path to the mounted SDCard. This is something I've implemented and it has worked so far.

public class StorageOptions {
    private static ArrayList<String> mMounts = new ArrayList<String>();
    private static ArrayList<String> mVold = new ArrayList<String>();

    public static String[] labels;
    public static String[] paths;
    public static int count = 0;
    private static final String TAG = StorageOptions.class.getSimpleName();

    public static void determineStorageOptions() {
        readMountsFile();

        readVoldFile();

        compareMountsWithVold();

        testAndCleanMountsList();

        setProperties();
    }

    private static void readMountsFile() {
        /*
         * 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
         */

        // some mount files don't list the default
        // path first, so we add it here to
        // ensure that it is first in our list
        mMounts.add("/mnt/sdcard");

        try {
            Scanner scanner = new Scanner(new File("/proc/mounts"));
            while (scanner.hasNext()) {
                String line = scanner.nextLine();
                if (line.startsWith("/dev/block/vold/")) {
                    String[] lineElements = line.split(" ");
                    String element = lineElements[1];

                    // don't add the default mount path
                    // it's already in the list.
                    if (!element.equals("/mnt/sdcard"))
                        mMounts.add(element);
                }
            }
        } catch (Exception e) {
            // Auto-generated catch block

            e.printStackTrace();
        }
    }

    private static void readVoldFile() {
        /*
         * Scan the /system/etc/vold.fstab file and look for lines like this:
         * dev_mount sdcard /mnt/sdcard 1
         * /devices/platform/s3c-sdhci.0/mmc_host/mmc0
         * 
         * 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
         */

        // some devices are missing the vold file entirely
        // so we add a path here to make sure the list always
        // includes the path to the first sdcard, whether real
        // or emulated.
        mVold.add("/mnt/sdcard");

        try {
            Scanner scanner = new Scanner(new File("/system/etc/vold.fstab"));
            while (scanner.hasNext()) {
                String line = scanner.nextLine();
                if (line.startsWith("dev_mount")) {
                    String[] lineElements = line.split(" ");
                    String element = lineElements[2];

                    if (element.contains(":"))
                        element = element.substring(0, element.indexOf(":"));

                    // don't add the default vold path
                    // it's already in the list.
                    if (!element.equals("/mnt/sdcard"))
                        mVold.add(element);
                }
            }
        } catch (Exception e) {
            // Auto-generated catch block

            e.printStackTrace();
        }
    }

    private static void compareMountsWithVold() {
        /*
         * Sometimes the two lists of mount points will be different. We only
         * want those mount points that are in both list.
         * 
         * Compare the two lists together and remove items that are not in both
         * lists.
         */

        for (int i = 0; i < mMounts.size(); i++) {
            String mount = mMounts.get(i);
            if (!mVold.contains(mount))
                mMounts.remove(i--);
        }

        // don't need this anymore, clear the vold list to reduce memory
        // use and to prepare it for the next time it's needed.
        mVold.clear();
    }

    private static void testAndCleanMountsList() {
        /*
         * Now that we have a cleaned list of mount paths Test each one to make
         * sure it's a valid and available path. If it is not, remove it from
         * the list.
         */

        for (int i = 0; i < mMounts.size(); i++) {
            String mount = mMounts.get(i);
            File root = new File(mount);
            if (!root.exists() || !root.isDirectory() || !root.canWrite())
                mMounts.remove(i--);
        }
    }

    @SuppressWarnings("unchecked")
    private static void setProperties() {
        /*
         * At this point all the paths in the list should be valid. Build the
         * public properties.
         */
        Constants.mMounts = new ArrayList<String>();
        ArrayList<String> mLabels = new ArrayList<String>();

        int j = 0;
        if (mMounts.size() > 0) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD)
                mLabels.add("Auto");
            else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
                if (Environment.isExternalStorageRemovable()) {
                    mLabels.add("External SD Card 1");
                    j = 1;
                } else
                    mLabels.add("Internal Storage");
            } else {
                if (!Environment.isExternalStorageRemovable()
                        || Environment.isExternalStorageEmulated())
                    mLabels.add("Internal Storage");
                else {
                    mLabels.add("External SD Card 1");
                    j = 1;
                }
            }

            if (mMounts.size() > 1) {
                for (int i = 1; i < mMounts.size(); i++) {
                    mLabels.add("External SD Card " + (i + j));
                }
            }
        }

        labels = new String[mLabels.size()];
        mLabels.toArray(labels);

        paths = new String[mMounts.size()];
        mMounts.toArray(paths);
        Constants.mMounts = (ArrayList<String>) mMounts.clone();
        Constants.mLabels = (ArrayList<String>) mLabels.clone();
        count = Math.min(labels.length, paths.length);

        // don't need this anymore, clear the mounts list to reduce memory
        // use and to prepare it for the next time it's needed.
        mMounts.clear();

    }
}

I found this off of a similar question from SO, that I dont have the link to unfortunately, but it s there on probably Sony's Android developer site(no links there either unfortunately). Wagic - a C++ game engine library implements the same and their code is here: http://wagic.googlecode.com/svn-history/r4300/trunk/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java so you could look at the implementation. I wish someone from Google can answer this question and provide a single way that reads the SDcard mount point from all Android devices

于 2013-08-05T05:40:02.163 回答
1

它并不像您想的那样简单, String f = Environment.getExternalStorageDirectory().getAbsolutePath(); Log.v("TAG",f);//打印sdcard的路径

它返回设备存储路径而不是外部 sdcard 路径。

于 2016-02-12T07:11:50.730 回答
-1

如果您尝试获取 SD 卡的路径,请使用此代码

String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();

然后使用它来获取特定文件夹/文件的路径

String path = baseDir + "/your folder(s)/" + fileName;

于 2013-08-05T04:23:44.413 回答
-6

这很简单。

String f = Environment.getExternalStorageDirectory().getAbsolutePath();
Log.v("TAG",f);//to print the path of sdcard

如果你想访问一个文件,那么。

String f =  Environment.getExternalStorageDirectory()+"/file.ext";
Log.v("TAG",f);//to print the path of file in Logcat.
于 2013-08-05T04:24:18.157 回答