Получить внешнее местоположение SDCard в Android

У меня есть приложение с огромными данными, предварительно сохраненными на SD-карте.

Мы поддерживаем все планшеты ICS вперед. Я не могу правильно найти доступ к местоположению SDCard на всех устройствах.

Я посмотрел на различные решения, приведенные здесь на SO, но они, похоже, не работают во всех случаях. Ищете общее решение.

Даже если кто-нибудь скажет мне все возможные точки монтирования SDCard.

Я нацелен на Android-планшеты, только если это может сузить решение.

Ответ 1

К сожалению, это распространенная проблема из-за того, что устройства Android сильно фрагментированы. Environment.getExternalStorageDirectory() относится к тому, что производитель устройства считает "внешним хранилищем". На некоторых устройствах это съемный носитель, например SD-карта. На некоторых устройствах это часть встроенной вспышки (http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()). Здесь "внешнее хранилище" означает "диск, доступный через USB Mass Storage при установке на хост-машине". Если производитель устройства выбрал внешнюю память на борту, а также имеет SD-карту, вам нужно будет связаться с этим производителем, чтобы определить, можете ли вы использовать SD-карту. Для большинства совместимых устройств Android (известных из списка соответствия Google) должен работать Environment.getExternalStorageDirectory(). Или вы можете написать собственный класс хранения, который смотрит на точки монтирования и дает правильный путь к смонтированной SDCard. Это то, что я реализовал, и он работает до сих пор.

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 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 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 needed.
        mVold.clear();
    }

    private static void testAndCleanMountsList() {
        /*
         * Now that we have a cleaned list of mount paths Test each one to make
         * sure it 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 needed.
        mMounts.clear();

    }
}

Я нашел это от аналогичного вопроса от SO, что у меня нет ссылки на, к сожалению, но это там, вероятно, на сайте разработчика Sony Android (к сожалению, ссылок нет). Wagic - библиотека движков движка С++ реализует то же самое, и их код здесь: http://wagic.googlecode.com/svn-history/r4300/trunk/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java поэтому вы можете посмотреть на реализацию. Я хочу, чтобы кто-то из Google смог ответить на этот вопрос и предоставить единственный способ, который читает точку подключения SDcard со всех Android-устройств.

Ответ 2

Это не просто, как вы думаете, Строка f = Environment.getExternalStorageDirectory(). GetAbsolutePath(); Log.v( "TAG", f);//для печати пути sdcard

Он возвращает путь хранения устройства не к внешнему пути SDK.

Ответ 3

Если вы пытаетесь получить путь к SD-карте, используйте этот код

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

Затем используйте это, чтобы получить путь к определенной папке/файлу

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

Ответ 4

Простой.

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.