Android Открыть каталог внешнего хранилища (sdcard) для хранения файла

Я хочу открыть путь к каталогу внешнего хранилища для программного сохранения файла. Я пытался, но не получил путь к SD-карте. Как я могу это сделать? Есть ли какое-либо решение для этого?

private File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "");

or

private File path = new File(Environment.getExternalStorageDirectory() + "");

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

Когда мы открываем память хранилища, если присутствует SD-карта, она будет отображаться, как показано ниже: введите описание изображения здесь

память устройства и SD-карта памяти.

Я хочу получить путь к памяти SD с помощью кодирования. Я дал разрешения в манифесте-

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

person yuva ツ    schedule 06.03.2014    source источник
comment
да. У меня есть разрешение WRITE_EXTERNAL STORAGE   -  person yuva ツ    schedule 06.03.2014
comment
Также добавьте разрешение READ_EXTERNAL STORAGE   -  person Chirag Ghori    schedule 06.03.2014
comment
@BlackTiger: все еще не получает путь к SD-карте   -  person yuva ツ    schedule 06.03.2014
comment
String root = Environment.getExternalStorageDirectory().toString(); Если вы все сделали правильно, он также вернет путь. Пожалуйста, опубликуйте свой полный код   -  person Rethinavel    schedule 06.03.2014
comment
Путь, который вы указали, такой же, как и тот, который я пробовал. Я разместил его. Я хочу путь к каталогу SD-карты. N то, что вы говорите, дает внутреннюю память / память устройства.   -  person yuva ツ    schedule 06.03.2014
comment
@yuvaツ используйте это, как я уже упоминал в своем ответе: String pathName = /mnt/; или используйте это: String pathName = /storage/;   -  person Farhan Shah    schedule 06.03.2014


Ответы (8)


У меня была точно такая же проблема!

Чтобы получить внутреннюю SD-карту, вы можете использовать

String extStore = System.getenv("EXTERNAL_STORAGE");
File f_exts = new File(extStore);

Чтобы получить внешнюю SD-карту, вы можете использовать

String secStore = System.getenv("SECONDARY_STORAGE");
File f_secs = new File(secStore);

При запуске кода

 extStore = "/storage/emulated/legacy"
 secStore = "/storage/extSdCarcd"

работает отлично!

person Rijul Gupta    schedule 30.05.2014
comment
также хорошо различать первичное внешнее и вторичное внешнее хранилище .. спасибо ... - person neeraj kirola; 30.06.2014
comment
Спасибо за ответ. Я добавил к нему дополнение, но оно не поместилось здесь, в комментариях. Установите свое имя в моем ответе как исходный ответ. - person Alexandre; 01.06.2015
comment
@neerajkirola посетите stackoverflow.com/a/29404440/2818583, чтобы узнать разницу между первичным внешним и вторичным внешним хранилищем. - person AnV; 29.07.2016
comment
System.getenv(SECONDARY_STORAGE) возвращает значение null, когда я пытался использовать эмулятор Android - person bikram; 25.10.2017
comment
@bikrampandit: это, скорее всего, потому, что у вас нет дополнительного запоминающего устройства, подключенного к эмулятору. Кроме того, я заметил, что новые версии Android объединили две памяти вместе для некоторых приложений, хотя я сомневаюсь, что это будет так. - person Rijul Gupta; 25.10.2017
comment
Не работает на Galaxy 7 Edge с Android 7. System.getenv("SECONDARY_STORAGE") возвращает значение null. но SDCard вставлена. - person BArtWell; 20.02.2018
comment
@BikramPandit SECONDARY_STORAGE может иметь другое строковое имя на разных устройствах. - person Muhammed Haris; 07.12.2018
comment
System.getenv(SECONDARY_STORAGE) возвращает null на моем телефоне с SD-картой. Есть идеи, почему Google сделал это таким излишне сложным? - person Paul McCarthy; 06.10.2019

Внутреннее хранилище называется в API «внешним хранилищем».

Как указано в документации по Среда.

Примечание: пусть вас не смущает слово «внешний». Этот каталог лучше рассматривать как медиа/общее хранилище. Это файловая система, которая может содержать относительно большой объем данных и является общей для всех приложений (не применяет разрешения). Традиционно это SD-карта, но она также может быть реализована как встроенное хранилище в устройстве, которое отличается от защищенного внутреннего хранилища и может быть смонтировано как файловая система на компьютере.

Чтобы определить, действительно ли Environment.getExternalStorageDirectory() возвращает физическое внутреннее или внешнее хранилище, вызовите Environment.isExternalStorageEmulated(). Если он эмулируется, то он внутренний. На более новых устройствах с внутренним хранилищем и слотом для SD-карты Environment.getExternalStorageDirectory() всегда будет возвращать внутреннее хранилище. В то время как на старых устройствах, которые имеют только SD-карту в качестве варианта хранения мультимедиа, он всегда будет возвращать SD-карту.

Невозможно получить все хранилища с помощью текущего Android API.

Я создал хелпер по методу Виталия Полчука в ответе ниже

Как можно Я получаю список подключенных внешних хранилищ Android-устройства

ПРИМЕЧАНИЕ. Запуск вторичного хранилища KitKat доступен только в режиме ТОЛЬКО ДЛЯ ЧТЕНИЯ. Вы можете проверить возможность записи, используя следующий метод.

/**
 * Checks whether the StorageVolume is read-only
 * 
 * @param volume
 *            StorageVolume to check
 * @return true, if volume is mounted read-only
 */
public static boolean isReadOnly(@NonNull final StorageVolume volume) {
    if (volume.mFile.equals(Environment.getExternalStorageDirectory())) {
        // is a primary storage, check mounted state by Environment
        return android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED_READ_ONLY);
    } else {
        if (volume.getType() == Type.USB) {
            return volume.isReadOnly();
        }
        //is not a USB storagem so it's read-only if it's mounted read-only or if it's a KitKat device
        return volume.isReadOnly() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    }
}

Класс StorageHelper

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;

import android.os.Environment;

public final class StorageHelper {

    //private static final String TAG = "StorageHelper";

    private StorageHelper() {
    }

    private static final String STORAGES_ROOT;

    static {
        final String primaryStoragePath = Environment.getExternalStorageDirectory()
                .getAbsolutePath();
        final int index = primaryStoragePath.indexOf(File.separatorChar, 1);
        if (index != -1) {
            STORAGES_ROOT = primaryStoragePath.substring(0, index + 1);
        } else {
            STORAGES_ROOT = File.separator;
        }
    }

    private static final String[] AVOIDED_DEVICES = new String[] {
        "rootfs", "tmpfs", "dvpts", "proc", "sysfs", "none"
    };

    private static final String[] AVOIDED_DIRECTORIES = new String[] {
        "obb", "asec"
    };

    private static final String[] DISALLOWED_FILESYSTEMS = new String[] {
        "tmpfs", "rootfs", "romfs", "devpts", "sysfs", "proc", "cgroup", "debugfs"
    };

    /**
     * Returns a list of mounted {@link StorageVolume}s Returned list always
     * includes a {@link StorageVolume} for
     * {@link Environment#getExternalStorageDirectory()}
     * 
     * @param includeUsb
     *            if true, will include USB storages
     * @return list of mounted {@link StorageVolume}s
     */
    public static List<StorageVolume> getStorages(final boolean includeUsb) {
        final Map<String, List<StorageVolume>> deviceVolumeMap = new HashMap<String, List<StorageVolume>>();

        // this approach considers that all storages are mounted in the same non-root directory
        if (!STORAGES_ROOT.equals(File.separator)) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader("/proc/mounts"));
                String line;
                while ((line = reader.readLine()) != null) {
                    // Log.d(TAG, line);
                    final StringTokenizer tokens = new StringTokenizer(line, " ");

                    final String device = tokens.nextToken();
                    // skipped devices that are not sdcard for sure
                    if (arrayContains(AVOIDED_DEVICES, device)) {
                        continue;
                    }

                    // should be mounted in the same directory to which
                    // the primary external storage was mounted
                    final String path = tokens.nextToken();
                    if (!path.startsWith(STORAGES_ROOT)) {
                        continue;
                    }

                    // skip directories that indicate tha volume is not a storage volume
                    if (pathContainsDir(path, AVOIDED_DIRECTORIES)) {
                        continue;
                    }

                    final String fileSystem = tokens.nextToken();
                    // don't add ones with non-supported filesystems
                    if (arrayContains(DISALLOWED_FILESYSTEMS, fileSystem)) {
                        continue;
                    }

                    final File file = new File(path);
                    // skip volumes that are not accessible
                    if (!file.canRead() || !file.canExecute()) {
                        continue;
                    }

                    List<StorageVolume> volumes = deviceVolumeMap.get(device);
                    if (volumes == null) {
                        volumes = new ArrayList<StorageVolume>(3);
                        deviceVolumeMap.put(device, volumes);
                    }

                    final StorageVolume volume = new StorageVolume(device, file, fileSystem);
                    final StringTokenizer flags = new StringTokenizer(tokens.nextToken(), ",");
                    while (flags.hasMoreTokens()) {
                        final String token = flags.nextToken();
                        if (token.equals("rw")) {
                            volume.mReadOnly = false;
                            break;
                        } else if (token.equals("ro")) {
                            volume.mReadOnly = true;
                            break;
                        }
                    }
                    volumes.add(volume);
                }

            } catch (IOException ex) {
                ex.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException ex) {
                        // ignored
                    }
                }
            }
        }

        // remove volumes that are the same devices
        boolean primaryStorageIncluded = false;
        final File externalStorage = Environment.getExternalStorageDirectory();
        final List<StorageVolume> volumeList = new ArrayList<StorageVolume>();
        for (final Entry<String, List<StorageVolume>> entry : deviceVolumeMap.entrySet()) {
            final List<StorageVolume> volumes = entry.getValue();
            if (volumes.size() == 1) {
                // go ahead and add
                final StorageVolume v = volumes.get(0);
                final boolean isPrimaryStorage = v.file.equals(externalStorage);
                primaryStorageIncluded |= isPrimaryStorage;
                setTypeAndAdd(volumeList, v, includeUsb, isPrimaryStorage);
                continue;
            }
            final int volumesLength = volumes.size();
            for (int i = 0; i < volumesLength; i++) {
                final StorageVolume v = volumes.get(i);
                if (v.file.equals(externalStorage)) {
                    primaryStorageIncluded = true;
                    // add as external storage and continue
                    setTypeAndAdd(volumeList, v, includeUsb, true);
                    break;
                }
                // if that was the last one and it's not the default external
                // storage then add it as is
                if (i == volumesLength - 1) {
                    setTypeAndAdd(volumeList, v, includeUsb, false);
                }
            }
        }
        // add primary storage if it was not found
        if (!primaryStorageIncluded) {
            final StorageVolume defaultExternalStorage = new StorageVolume("", externalStorage, "UNKNOWN");
            defaultExternalStorage.mEmulated = Environment.isExternalStorageEmulated();
            defaultExternalStorage.mType =
                    defaultExternalStorage.mEmulated ? StorageVolume.Type.INTERNAL
                            : StorageVolume.Type.EXTERNAL;
            defaultExternalStorage.mRemovable = Environment.isExternalStorageRemovable();
            defaultExternalStorage.mReadOnly =
                    Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
            volumeList.add(0, defaultExternalStorage);
        }
        return volumeList;
    }

    /**
     * Sets {@link StorageVolume.Type}, removable and emulated flags and adds to
     * volumeList
     * 
     * @param volumeList
     *            List to add volume to
     * @param v
     *            volume to add to list
     * @param includeUsb
     *            if false, volume with type {@link StorageVolume.Type#USB} will
     *            not be added
     * @param asFirstItem
     *            if true, adds the volume at the beginning of the volumeList
     */
    private static void setTypeAndAdd(final List<StorageVolume> volumeList,
            final StorageVolume v,
            final boolean includeUsb,
            final boolean asFirstItem) {
        final StorageVolume.Type type = resolveType(v);
        if (includeUsb || type != StorageVolume.Type.USB) {
            v.mType = type;
            if (v.file.equals(Environment.getExternalStorageDirectory())) {
                v.mRemovable = Environment.isExternalStorageRemovable();
            } else {
                v.mRemovable = type != StorageVolume.Type.INTERNAL;
            }
            v.mEmulated = type == StorageVolume.Type.INTERNAL;
            if (asFirstItem) {
                volumeList.add(0, v);
            } else {
                volumeList.add(v);
            }
        }
    }

    /**
     * Resolved {@link StorageVolume} type
     * 
     * @param v
     *            {@link StorageVolume} to resolve type for
     * @return {@link StorageVolume} type
     */
    private static StorageVolume.Type resolveType(final StorageVolume v) {
        if (v.file.equals(Environment.getExternalStorageDirectory())
                && Environment.isExternalStorageEmulated()) {
            return StorageVolume.Type.INTERNAL;
        } else if (containsIgnoreCase(v.file.getAbsolutePath(), "usb")) {
            return StorageVolume.Type.USB;
        } else {
            return StorageVolume.Type.EXTERNAL;
        }
    }

    /**
     * Checks whether the array contains object
     * 
     * @param array
     *            Array to check
     * @param object
     *            Object to find
     * @return true, if the given array contains the object
     */
    private static <T> boolean arrayContains(T[] array, T object) {
        for (final T item : array) {
            if (item.equals(object)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether the path contains one of the directories
     * 
     * For example, if path is /one/two, it returns true input is "one" or
     * "two". Will return false if the input is one of "one/two", "/one" or
     * "/two"
     * 
     * @param path
     *            path to check for a directory
     * @param dirs
     *            directories to find
     * @return true, if the path contains one of the directories
     */
    private static boolean pathContainsDir(final String path, final String[] dirs) {
        final StringTokenizer tokens = new StringTokenizer(path, File.separator);
        while (tokens.hasMoreElements()) {
            final String next = tokens.nextToken();
            for (final String dir : dirs) {
                if (next.equals(dir)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Checks ifString contains a search String irrespective of case, handling.
     * Case-insensitivity is defined as by
     * {@link String#equalsIgnoreCase(String)}.
     * 
     * @param str
     *            the String to check, may be null
     * @param searchStr
     *            the String to find, may be null
     * @return true if the String contains the search String irrespective of
     *         case or false if not or {@code null} string input
     */
    public static boolean containsIgnoreCase(final String str, final String searchStr) {
        if (str == null || searchStr == null) {
            return false;
        }
        final int len = searchStr.length();
        final int max = str.length() - len;
        for (int i = 0; i <= max; i++) {
            if (str.regionMatches(true, i, searchStr, 0, len)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Represents storage volume information
     */
    public static final class StorageVolume {

        /**
         * Represents {@link StorageVolume} type
         */
        public enum Type {
            /**
             * Device built-in internal storage. Probably points to
             * {@link Environment#getExternalStorageDirectory()}
             */
            INTERNAL,

            /**
             * External storage. Probably removable, if no other
             * {@link StorageVolume} of type {@link #INTERNAL} is returned by
             * {@link StorageHelper#getStorages(boolean)}, this might be
             * pointing to {@link Environment#getExternalStorageDirectory()}
             */
            EXTERNAL,

            /**
             * Removable usb storage
             */
            USB
        }

        /**
         * Device name
         */
        public final String device;

        /**
         * Points to mount point of this device
         */
        public final File file;

        /**
         * File system of this device
         */
        public final String fileSystem;

        /**
         * if true, the storage is mounted as read-only
         */
        private boolean mReadOnly;

        /**
         * If true, the storage is removable
         */
        private boolean mRemovable;

        /**
         * If true, the storage is emulated
         */
        private boolean mEmulated;

        /**
         * Type of this storage
         */
        private Type mType;

        StorageVolume(String device, File file, String fileSystem) {
            this.device = device;
            this.file = file;
            this.fileSystem = fileSystem;
        }

        /**
         * Returns type of this storage
         * 
         * @return Type of this storage
         */
        public Type getType() {
            return mType;
        }

        /**
         * Returns true if this storage is removable
         * 
         * @return true if this storage is removable
         */
        public boolean isRemovable() {
            return mRemovable;
        }

        /**
         * Returns true if this storage is emulated
         * 
         * @return true if this storage is emulated
         */
        public boolean isEmulated() {
            return mEmulated;
        }

        /**
         * Returns true if this storage is mounted as read-only
         * 
         * @return true if this storage is mounted as read-only
         */
        public boolean isReadOnly() {
            return mReadOnly;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((file == null) ? 0 : file.hashCode());
            return result;
        }

        /**
         * Returns true if the other object is StorageHelper and it's
         * {@link #file} matches this one's
         * 
         * @see Object#equals(Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final StorageVolume other = (StorageVolume) obj;
            if (file == null) {
                return other.file == null;
            }
            return file.equals(other.file);
        }

        @Override
        public String toString() {
            return file.getAbsolutePath() + (mReadOnly ? " ro " : " rw ") + mType + (mRemovable ? " R " : "")
                    + (mEmulated ? " E " : "") + fileSystem;
        }
    }
}
person Yaroslav Mytkalyk    schedule 06.03.2014
comment
Он по-прежнему возвращает значение null, если вы удалите StringUtils.containsIgnoreCase() и просто вернете первый найденный вариант чтения-записи-выполнения? - person Yaroslav Mytkalyk; 06.03.2014
comment
Если я удалю условие, возвращающее путь к каталогу устройства - person yuva ツ; 06.03.2014
comment
Я имею в виду не удалять первый if, а StringUtils-one if. Можете ли вы дать мне вывод adb shell ls/storage? - person Yaroslav Mytkalyk; 06.03.2014
comment
/хранилище/эмулированные/устаревшие - person yuva ツ; 06.03.2014
comment
Мой подход работал на всех устройствах, которые я пробовал, но я думаю, что это не лучший способ. Хорошо, что я понял это, потому что собирался использовать это в производстве. Каково реальное местоположение SD-карты, найденной в сторонних приложениях на вашем устройстве (и имя устройства, пожалуйста)? Мой подход работает, если внешний находится в /storage/emulated/dir. Когда adb shell ls /storage/emulated/ печатает? - person Yaroslav Mytkalyk; 06.03.2014
comment
Вы можете попробовать этот ответ, тогда stackoverflow.com/a/19982338/1366471 мне это не очень нравится, я бы мы изменили несколько пунктов, например разрешили ntfs помимо vfat и т. д., но в целом монтирование для чтения было бы более надежным. - person Yaroslav Mytkalyk; 06.03.2014
comment
давайте продолжим это обсуждение в чате - person yuva ツ; 06.03.2014
comment
извините, мой вывод с использованием оболочки adb: shell@android:/storage $ ls UsbDriveA UsbDriveB UsbDriveC UsbDriveD UsbDriveE UsbDriveF эмулированный extSdCard sdcard0 - person yuva ツ; 06.03.2014
comment
я пробовал по ссылке, которую вы дали. все еще не получается - person yuva ツ; 06.03.2014
comment
окончательный List‹StorageVolume› хранилища = getStorages(false); затем определите, какая из них является реальной SDCard, с помощью storageVolume.isRemovable(). и получить каталог по storageVolume.file - person Yaroslav Mytkalyk; 07.05.2014
comment
в вышеприведенном классе нет никакого метода getStorage(); - person yuva ツ; 07.05.2014
comment
Что значит нет? Я ясно вижу StorageHelper.getStorages(boolean) метод. - person Yaroslav Mytkalyk; 07.05.2014

принимая ответ @rijul вперед, он не работает в версиях зефира и выше:

       //for pre-marshmallow versions
       String path = System.getenv("SECONDARY_STORAGE");

       // For Marshmallow, use getExternalCacheDirs() instead of System.getenv("SECONDARY_STORAGE")
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
           File[] externalCacheDirs = mContext.getExternalCacheDirs();
           for (File file : externalCacheDirs) {
               if (Environment.isExternalStorageRemovable(file)) {
                   // Path is in format /storage.../Android....
                   // Get everything before /Android
                   path = file.getPath().split("/Android")[0];
                   break;
               }
           }
       }


        // Android avd emulator doesn't support this variable name so using other one
        if ((null == path) || (path.length() == 0))
            path = Environment.getExternalStorageDirectory().getAbsolutePath();
person Shubham    schedule 29.06.2017

надеюсь, это сработало для вас:

File yourFile = new File(Environment.getExternalStorageDirectory(), "textarabics.txt");

Это даст нам путь к SD-карте:

File path = Environment.getExternalStorageDirectory();

Попробуй это:

String pathName = "/mnt/";

или попробуйте это:

String pathName = "/storage/";
person Farhan Shah    schedule 06.03.2014
comment
Это зависит от устройства. Для разных устройств - person yuva ツ; 06.03.2014
comment
@FarhanShah первые два варианта не показывают ничего нового для ОП. Вторые два (/mnt или /storage) могут быть точками монтирования, но не фактическим внешним хранилищем, а плюс точка монтирования в любом случае различается, поэтому ответ бесполезен с двумя первыми утверждениями и вводит в заблуждение со вторыми двумя. - person Yaroslav Mytkalyk; 06.03.2014
comment
@DoctororDrive, я стараюсь изо всех сил и искренне ответил на ОП, поэтому нет причин для понижения голоса. - person Farhan Shah; 06.03.2014
comment
@FarhanShah ответ может быть отклонен, если он не отвечает на вопрос или неверен. На мой взгляд, неважно, старались ли вы изо всех сил или нет - это плохой ответ. Люди делают ошибки, и система голосования создана для измерения полезности ответа. - person Yaroslav Mytkalyk; 06.03.2014

Дополняю ответ rijul gupta:

String strSDCardPath = System.getenv("SECONDARY_STORAGE");

    if ((strSDCardPath == null) || (strSDCardPath.length() == 0)) {
        strSDCardPath = System.getenv("EXTERNAL_SDCARD_STORAGE");
    }

    //If may get a full path that is not the right one, even if we don't have the SD Card there. 
    //We just need the "/mnt/extSdCard/" i.e and check if it's writable
    if(strSDCardPath != null) {
        if (strSDCardPath.contains(":")) {
            strSDCardPath = strSDCardPath.substring(0, strSDCardPath.indexOf(":"));
        }
        File externalFilePath = new File(strSDCardPath);

        if (externalFilePath.exists() && externalFilePath.canWrite()){
            //do what you need here
        }
    }
person Alexandre    schedule 01.06.2015

Я хочу открыть путь к каталогу внешнего хранилища для программного сохранения файла. Я пытался, но не получил путь к SD-карте. Как я могу это сделать? Есть ли какое-либо решение для этого?

Чтобы сохранить файлы вашего приложения на SD-карте, вы должны использовать метод File[] getExternalFilesDirs (String type) в классе Context. Как правило, вторым возвращаемым путем будет путь хранения карты microSD (если она есть).

На моем телефоне второй возвращенный путь был /storage/sdcard1/Android/data/your.application.package.appname/files после передачи null в качестве аргумента getExternalFilesDirs (String type). Но путь может отличаться на разных телефонах, разных версиях Android.

И File getExternalStorageDirectory (), и File getExternalStoragePublicDirectory (String type) в классе Environment могут возвращать каталог SD-карты или каталог внутренней памяти в зависимости от модели вашего телефона и версии ОС Android.

Поскольку согласно официальному руководству Android, внешнее хранилище может быть

съемный носитель (например, SD-карта) или внутреннее (несъемное) хранилище.

Терминология внутреннего и внешнего хранилища согласно Google/официальной документации Android совершенно отличается от того, что мы думаем.

person AnV    schedule 01.08.2016

да, это может работать в KITKAT.

выше KITKAT+ он будет идти во внутреннюю память: пути вроде (хранилище/эмулированные/0).

пожалуйста, подумайте, как «приложение Xender» дает разрешение на запись на внешнюю SD-карту.

Итак, к счастью, в Android 5.0 и более поздних версиях появился новый официальный способ записи приложений на внешнюю SD-карту. Приложения должны запрашивать у пользователя разрешение на запись в папку на SD-карте. Они открывают диалог выбора системной папки. Пользователю необходимо перейти в эту конкретную папку и выбрать ее.

для получения более подробной информации см. https://metactrl.com/docs/sdcard-on-lollipop/

person Muhammed Haris    schedule 07.12.2018

Попробуйте использовать

new File(Environment.getExternalStorageDirectory(),"somefilename");

И не забудьте добавить разрешения WRITE_EXTERNAL STORAGE и READ_EXTERNAL STORAGE.

person Hafizh Herdi    schedule 06.03.2014