Каталог Android Open External Storage (sdcard) для хранения файла

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

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

или

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

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

Когда мы открываем память памяти, если sdcard присутствует, она будет отображаться как ниже, Введите описание изображения здесь

Устройство хранения & 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" /> 

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

Чтобы получить внутреннюю 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" 

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

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

Как упоминалось в документации по охране окружающей среды

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

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

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

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

Как я могу получить список смонтированных внешних хранилищ Android-устройства

ПРИМЕЧАНИЕ. Начальное дополнительное хранилище KitKat доступно только как READ-ONLY , вы можете проверить возможность записи с помощью следующего метода

 /** * 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; } } } 

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

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

Это даст u sdcard путь:

 File path = Environment.getExternalStorageDirectory(); 

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

 String pathName = "/mnt/"; 

Или попробуйте следующее:

 String pathName = "/storage/"; 

Дополнение 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/" ie 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 } } 

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

Чтобы сохранить файлы приложений на 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 Guide внешнее хранилище может быть

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

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

Если вы хотите узнать больше о различиях терминологии, classes и methods сохранения файлов во внутреннем и внешнем хранилищах, пути хранения; Я написал длинную запись в документации stackoverflow с ясным объяснением. Вы можете просмотреть его здесь: Внутреннее и внешнее хранилище в Android – Уточнение терминологии

Принимая ответ @ 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(); 

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

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

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