Android studio environment getexternalstoragedirectory

Хранение данных и файлов

В целом хранение файлов и данных можно условно разделить на две группы: во внутреннем или внешнем хранилище. Но разница между ними довольна тонка. В целом политика Гугла в отношение данных ужесточается с каждой версии системы.

Android поддерживает различные варианты хранения данных и файлов.

  • Специфичные для приложения файлы. Доступ к файлам имеет только приложение, их создавшее. Файлы могут находиться во внутреннем и внешнем хранилище. У других приложений нет доступа (кроме случаев, когда файлы хранятся на внешнем хранилище). Методы getFilesDir(), getCacheDir(), getExternalFilesDir(), getExternalCacheDir(). Разрешений на доступ не требуется. Файлы удаляются, когда приложение удаляется пользователем.
  • Разделяемое хранилище. Приложение может создавать файлы, которыми готово поделиться с другими приложениями — медиафайлы (картинки, видео, аудио), документы. Для медифайлов требуется разрешение READ_EXTERNAL_STORAGE или WRITE_EXTERNAL_STORAGE.
  • Настройки. Хранение простых данных по принципу ключ-значение. Доступно внутри приложения. Реализовано через Jetpack Preferences. Настройки удаляются, когда приложение удаляется пользователем.
  • Базы данных. Хранение данных в SQLite. На данный момент реализовано через библиотеку Room. Доступ только у родного приложения.

В зависимости от ваших потребностей, нужно выбрать нужный вариант хранения данных.

Следует быть осторожным при работе с внутренним и внешним хранилищем. Внутренне хранилище всегда есть в системе, но оно может быть не слишком большим по объёму. Вдобавок к внутреннему хранилищу, устройство может иметь внешнее хранилище. В старых моделях таким хранилищем выступала съёмная SD-карта. Сейчас чаще используют встроенную и недоступную для извлечения флеш-память. Если ваше приложение слишком большое, можно попросить систему устанавливать программу во внешнее хранилище, указав просьбу в манифесте.

В разных версиях Android требования к разрешению для работы с внешним хранилищем постоянно менялись. На данный момент (Android 10, API 29) требования выглядят следующим образом.

Приложение может иметь доступ к собственным файлам, которые находятся во внешнем хранилище. Также может получить доступ к определённым общим файлам на внешнем хранилище.

Доступ к общим файлам достигается через FileProvider API или контент-провайдеры.

Для просмотра файлов через студию используйте инструмент Device File Explorer.

Внешняя карта памяти

Когда появились первые устройства на Android, то практически у всех были внешние карточки памяти, которые вставлялись в телефон. Обычно там хранили фотки, видео и свои файлы. Всё было понятно — были различные методы для доступа к файловой системе. А потом началась чехарда. В телефонах также была и собственная «внешняя» память. Она вроде как и внешняя, но вставлена на заводе и вытащить её пользователь не мог, т.е. практически внутренняя. Затем пошла мода на телефоны, у которых была только такая внутреннее-внешняя карта. Пользователи поворчали, но привыкли. Сейчас встречаются оба варианта. Как правило, у телефонов с спрятанной картой больше памяти и выше степень водонепроницаемости.

Подобные фокусы с картой породили и другую проблему — Гугл озаботился безопасностью файлов и стала думать, как осложнить жизнь разработчику. С выходом каждой новой версии системы компания то давала добро на полный доступ к карточке, то ограничивала, то давала права с ограничениями, то откатывала свои решения назад. Короче, запутались сами и запутали всех.

Попробуем немного разобраться с этим зоопарком. Но помните, что процесс путаницы продолжается.

При подготовке материала я опирался на письма некоторых читателей сайта, которые присылали свои мысли по этому поводу. Спасибо им за структуризацию материала.

Вот что я (кажется) понял, попытавшись загрузить картинку с внешней SD карточки.

External это не External
«EXTERNAL_STORAGE» называется так не потому, что это внешняя память по отношению к устройству, а потому что она выглядит как внешняя память для компьютера, если устройство подключить кабелем к компьютеру. Причём именно выглядит, потому что обмен идёт по протоколу MTP – устройство только показывает компьютеру список папок и файлов, а при необходимости открыть или скопировать файл он специально загружается на компьютер, в отличие от настоящей флешки, файлы которой становятся файлами в файловой системе самого компьютера. Обмен по MTP позволяет устройству продолжать работать, когда оно подключено к компьютеру.

Читайте также:  Android car radio 2015

Emulated это не Emulated
Сначала я пытался прочесть файл с карточки на эмуляторе (из этого так ничего и не вышло). Функция getExternalStorageDirectory() давала мне /storage/emulated/0, и я думал, что «emulated» – это потому что на эмуляторе. Но когда я подцепил реальный планшет, слово «emulated» никуда не исчезло. Я стал рыться в интернете и обнаружил, что «Emulated storage is provided by exposing a portion of internal storage through an emulation layer and has been available since Android 3.0.» – то есть это просто кусок внутренней памяти, которая путём какой-то эмуляции делается доступной для пользователя, в отличие от собственно внутренней памяти.

При этом с точки зрения системы доступная для пользователя папка называется /storage/emulated/0, а при подключении к компьютеру по USB это просто одна из двух главных папок устройства – у меня в Windows Explorer она называется Tablet. Вторая папка у меня называется Card, и это и есть настоящая внешняя карточка.

Нет стандартных средств добраться из приложения до файлов на внешней карточке. Все попытки добраться до настоящей внешней карточки делаются с помощью неких трюков. Самое интересное, что я нашел, это статья на http://futurewithdreams.blogspot.com/2014/01/get-external-sdcard-location-in-android.html — парень читает таблицу смонтированных устройств /proc/mounts, таблицу volume daemons /system/etc/vold.fstab, сравнивает их и выбирает те тома, которые оказываются съёмными (с помощью Environment.isExternalStorageRemovable()).

Оказалось, что несистемным приложениям в принципе запрещено напрямую обращаться к съёмной карточке! Похоже, что это было так всегда, но вот начиная с версии Android 6 Marshmallow написано: внешняя карточка может быть определена как Portable либо Adoptable. Adoptable – это как бы «усыновляемая» память которая может быть «adopted», то есть взята в систему (примерно как кот с улицы в дом – это тоже называется to adopt) и использована как внутренняя. Для этого ее надо особым образом отформатировать и не вынимать, иначе не факт, что система продолжит нормально работать.

Portable – это нормальная съёмная карточка, но несистемным приложениям запрещено обращаться из программ к файлам на ней! Вот что написано в https://source.android.com/devices/storage/traditional.html:

Android 6.0 supports portable storage devices which are only connected to the device for a short period of time, like USB flash drives. When a user inserts a new portable device, the platform shows a notification to let them copy or manage the contents of that device. In Android 6.0, any device that is not adopted is considered portable. Because portable storage is connected for only a short time, the platform avoids heavy operations such as media scanning. Third-party apps must go through the Storage Access Framework to interact with files on portable storage; direct access is explicitly blocked for privacy and security reasons.

Если я правильно понял, этот самый Storage Access Framework позволяет работать с документом на карточке через диалог (открыть файл/сохранить файл), а вот прочитать или записать файл на карточке непосредственно из программы невозможно.

Общий вывод – реально из программы можно работать только с файлами на предоставляемой пользователю части встроенной памяти устройства, а на съёмной карточке – нет.

Это напоминает войну Microsoft с пользователями и разработчиками по поводу диска C:, компания уговаривала не устраивать беспорядок в корне этого диска, а ещё лучше — перенести свои файлы на другой диск. Но явных запретов не было.

Состояние на текущий момент

Гугл утверждает, что с версии Android 10 Q стандартный доступ к файлам будет прекращён. Ещё в Android 4.4 появился Storage Access Framework, который и должен стать заменой для работы с файлами.

Методы Environment.getExternalStorageDirectory() и Environment.getExternalStoragePublicDirectory() признаны устаревшими и будут недоступны. Даже если они будут возвращать корректные значения, ими вы не сможете воспользоваться.

В Android 7.0 добавили исключение FileUriExposedException, чтобы разработчики перестали использовать схему file://Uri.

Можно создавать файлы в корневой папке карточки при помощи Environment.getExternalStorageDirectory(), а также папки с вложенными файлами. Если папка уже существует, то у вас не будет доступа на запись (если это не ваша папка).

Если вы что-то записали, то сможете и прочитать. Чужое читать нельзя.

Кстати, разрешения на чтение и запись файлов не требуются, а READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE объявлены устаревшими.

Читайте также:  Робот для управления андроидом

Другие приложения не могут получить доступ к файлам вашего приложения. Файлы, которые вы создали через getExternalFilesDir(), доступны через Storage Access Framework, кроме файлов, созданных в корне карточки (что-то я совсем запутался). Ещё можно дать доступ через FileProvider.

При подключении USB-кабеля через getExternalFilesDir(), вы можете увидеть свои файлы и папки, а также файлы и папки пользователя. При этом файлы и папки пользователя на корневой папке вы не увидите. Вам не поможет даже adb или Device File Explorer студии.

Что делать?

Пользуйтесь методами класса Context, типа getExternalFilesDir(), getExternalCacheDir(), getExternalMediaDirs(), getObbDir() и им подобными, чтобы найти место для записи.

Используйте Storage Access Framework.

Используйте MediaStore для мультимедийных файлов.

Используйте FileProvider, чтобы файлы были видимы другим приложениям через ACTION_VIEW/ACTION_SEND.

Android 10: Появился новый флаг android:allowExternalStorageSandbox=»false» и метод Environment.isExternalStorageSandboxed() для работы с песочницей. Флаг android:requestLegacyExternalStorage=»true» для приложений, которые ещё используют старую модель доступа к файлам.

Как временное решение можно добавить в блок манифеста application атрибут android:requestLegacyExternalStorage=»true», чтобы доступ к файлам был как раньше в Android 4.4-9.0.

Android 11

Если вы создаёте файловый менеджер, то ему нужны возможности для просмотра файлов. Для этого следует установить разрешение MANAGE_EXTERNAL_STORAGE или использовать атрибут android:requestLegacyExternalStorage=»true» (см. выше).

Источник

Environment.getExternalStorageDirectory does not return the path to the removable storage

As of API level 8, it seems Android has redefined what «external» storage is. Reading through http://developer.android.com/reference/android/os/Environment.html, attached to the documentation for getExternalStorageDirectory I see the comment: «don’t be confused by the word ‘external’ here. This directory can better be thought as media/shared storage. In devices with multiple ‘external’ storage directories. , this directory represents the ‘primary’ external storage that the user will interact with.»

My app writes files to the path obtained by getExternalStorageDirectory , and I’ve had users ask for an option to write to their removable SD card instead. I had always assumed that getExternalStorageDirectory returned the path to the removable SD card, but this is no longer true. How do I access the path to this SD card?

3 Answers 3

According to the source, getExternalStorageDirectory is implemented to return whatever is set as «external storage» in the device environment:

and EXTERNAL_STORAGE_DIRECTORY is:

In contrast, getExternalStoragePublicDirectory(String type) requires one of these strings:

DIRECTORY_MUSIC, DIRECTORY_PODCASTS, DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS, DIRECTORY_PICTURES, DIRECTORY_MOVIES, DIRECTORY_DOWNLOADS, or DIRECTORY_DCIM. May not be null.

so it is not meant to return the sd-card root.

An alternative:

Finally, getExternalStorageState() will return the filesystem mounted in /mnt/sdcard/ . According to CommonsWare in this answer: Find an external SD card location, there is no way to directly get the external sdcard (if it even exist).

An alternative would be to check isExternalStorageRemovable () and give a manual option if it is false.

Источник

Android Tutorial: Android External Storage

Tutorial about how to use Android external storage.

1 What is Android external storage?

What Android «external storage» means is described in Android SDK Document:

Every Android-compatible device supports a shared «external storage» that you can use to save files. This can be a removable storage media (such as an SD card) or an internal (non-removable) storage. Files saved to the external storage are world-readable and can be modified by the user when they enable USB mass storage to transfer files on a computer.

So don’t be confused by the word «external» here. External storage can better be thought as media or shared storage. Traditionally this is an removable SD (Secure Digital) card, but it may also be implemented as built-in non-removable storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer.

2 Why external storage?

Android has already provided efficient internal storage for application, but still there is much need for external storage under certain circumstance.

  1. Need more memory or disk space to save big files;
  2. Let data saved or generated in your application be accessed by other applications;
  3. Some saved data should not be deleted although your application is uninstalled. For example, pictures, videos downloaded by your application.

3 Android external storage APIs Overview

Main APIs for Android external storage.

  • Environment.getExternalStorageDirectory() : return the primary external storage root directory.
  • Context.getExternalFilesDir(String type) : return the absolute path of the directory on the primary external storage where the application can place its own files.
  • Context.getExternalCacheDir() | return reference to your application specific path of cache directory on external storage.
  • Environment.getExternalStoragePublicDirectory(String type) | return public external storage directory for saving files of a particular type.
Читайте также:  Отключить виджеты андроид как

Following figure gives an overview of Android external storage APIs.

3.1 Environment.getExternalStorageDirectory()

Environment.getExternalStorageDirectory() returns top-level directory of the primary external storage.

If device has multiple external storage directories, returned directory represents the primary external storage that the user will interact with. There is also APIs available for accessing secondary storage or getting external storage directories list.

  • Context.getExternalFilesDirs(String type)
  • Context.getExternalCacheDirs()
  • Context.getExternalMediaDirs()

It is noticed that the returned directory of Environment.getExternalStorageDirectory() is the top-level directory of the external storage. You application should avoid placing files directly under this top-level directory. If your application needs save public or shared data, you’d better use directory returned by getExternalStoragePublicDirectory(String type) ; on the other hand, if your application only needs to store its own internal data on external storage, you’d better consider using getExternalFilesDir(String) or getExternalCacheDir() instead.

3.2 Context.getExternalFilesDir(String type)

Returns the absolute path to the directory on the primary shared or external storage device where the application can place persistent files it owns. These files are internal to the application.

The returned directory is owned by the application and its contents will be deleted when the application is uninstalled.

The type parameter can be null or one of the following constant value.

  • Environment.DIRECTORY_MUSIC
  • Environment.DIRECTORY_PODCASTS
  • Environment.DIRECTORY_RINGTONES
  • Environment.DIRECTORY_ALARMS
  • Environment.DIRECTORY_NOTIFICATIONS
  • Environment.DIRECTORY_PICTURES
  • Environment.DIRECTORY_MOVIES

If the type parameter is null , the returned path will be the root the files directory; otherwise, will be a sub directory of the given type.

3.3 Context.getExternalCacheDir()

Returns absolute path to application-specific directory on the primary shared or external storage device where the application can place cache files it owns.

Cached files under returned directory will be deleted when the application is uninstalled. Android platform does not always monitor the space available in shared storage, and thus may not automatically delete these cached files. Your application itself should always manage the maximum space used in this location.

3.4 Environment.getExternalStoragePublicDirectory(String type)

Get a top-level shared or external storage directory for placing files of a particular type.

The type parameter CAN NOT be null , should be one of the following constant value.

  • Environment.DIRECTORY_MUSIC
  • Environment.DIRECTORY_PODCASTS
  • Environment.DIRECTORY_RINGTONES
  • Environment.DIRECTORY_ALARMS
  • Environment.DIRECTORY_NOTIFICATIONS
  • Environment.DIRECTORY_PICTURES
  • Environment.DIRECTORY_MOVIES

Because this returned directory is public and is for shared files, you application should be careful and avoid erasing any files here.

4 How to Use Android external storage

External storage of Android device may not always be available, for example:

  • external storage may not be accessible if it has been mounted by users on their computer;
  • external storage has been removed from device.

So the first step is to check state of the external storage. External storage state can be checked using Environment.getExternalStorageState(File path) . More details can refer to Android Tutorial: Check SD Card Status.

The second step is to add android.permission.READ_EXTERNAL_STORAGE or android.permission.WRITE_EXTERNAL_STORAGE permission to your application.

Note: From Android 6.0+, application has to ask user for a permission one-by-one at runtime instead of being granted any permission at installation time.

The third step is to get File object reference of external storage directory.

Lastly, write or read data using common java.io APIs with the directory File object.

5 Android external storage example

There are two main features in this simple demo:

  • Show various external storage full path using Toast ;
  • Try to write demo file to external storage;

Main UI of the demo looks like screenshot below.

5.1 Add WRITE_EXTERNAL_STORAGE permission

Add android.permission.WRITE_EXTERNAL_STORAGE permission to AndroidManifest.xml file of your Android application project.

5.2 Helper method to check external storage state

Create a helper method in Activity class to check external storage state.

5.3 Helper method to write file

Create a common helper method to write string to a file.

5.4 Listen button clicking

Lastly, implement View.OnClickListener interface in the demo Activity.

You can check the saved file via file explore of Android Device Monitor (DDMS) in Android Studio or Eclipse.

Источник

Оцените статью