Path external storage android

Содержание
  1. Получение пути к карте памяти SD Card на Android
  2. Терминология
  3. Результаты поиска
  4. Описание кода
  5. Пример использования
  6. Заключение
  7. Android Tutorial: Android External Storage
  8. 1 What is Android external storage?
  9. 2 Why external storage?
  10. 3 Android external storage APIs Overview
  11. 3.1 Environment.getExternalStorageDirectory()
  12. 3.2 Context.getExternalFilesDir(String type)
  13. 3.3 Context.getExternalCacheDir()
  14. 3.4 Environment.getExternalStoragePublicDirectory(String type)
  15. 4 How to Use Android external storage
  16. 5 Android external storage example
  17. 5.1 Add WRITE_EXTERNAL_STORAGE permission
  18. 5.2 Helper method to check external storage state
  19. 5.3 Helper method to write file
  20. 5.4 Listen button clicking
  21. Android Storage: Internal, External, Removable. Часть 1/3
  22. Internal Storage
  23. То, что пользователи считают Internal Storage
  24. Что Google считает Internal Storage
  25. Где хранится Internal Storage … Иногда
  26. Где хранится Internal Storage … Остальное время
  27. Исследуем Internal Storage
  28. Ограничения внутреннего хранилища
  29. F.A.Q. по Internal Storage
  30. Должен ли я делать файлы во внутреннем хранилище World-Readable или World-Writeable?
  31. Ну, а как насчет android:sharedUserId ?
  32. Как запретить пользователям rooted устройств доступ к моим файлам во внутреннем хранилище?

Получение пути к карте памяти SD Card на Android

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

Итак, начнем с теории.

Терминология

Гугл нам говорит, что есть следующие понятия:

  1. Внутренняя (internal) память — это часть встроенной в телефон карты памяти. При ее использовании по умолчанию папка приложения защищена от доступа других приложений (Using the Internal Storage).
  2. Внешняя (external) память — это общее «внешнее хранилище», т.е. это может быть как часть встроенной памяти, так и удаляемое устройство. Обычно это часть встроенной памяти, как удаляемое устройство я видел в последний раз на андройде 2.2, где встроенная память была около 2Гб, и подключаемая память становилась внешней (Using the External Storage).
  3. Удаляемая (removable) память — все хранилища, которые могут быть удалены из устройства без «хирургических» вмешательств.

До версии KitKat 4.4 API не предоставляло функционала для получения путей к внешней памяти. Начиная с этой версии (API 19) появилась функция public abstract File[] getExternalFilesDirs (String type), которая возвращает массив строк с путями к внутренней и внешней памяти. Но как же быть с нашей SD Card, которая вставлена в слот? Путь к ней мы опять не можем получить.

Результаты поиска

Чтобы ответить на поставленный вопрос я обратился к всезнающему гуглу. Но и он мне не дал четкого ответа. Было рассмотрено множество вариантов определения от использования стандартных функций, которые ведут к внешней памяти, но ничего общего с удаляемыми устройствами хранения данных они не имеют, до обработки правил монтирования устройств (Android же на ядре Linux работает). В последних случаях были использованы «зашитые» пути к папке с примонтироваными устройствами (в различных версиях эта директория разная). Не стоит забывать, что от версии к версии правила монтирования меняются.

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

Описание кода

Был создан класс MountDevice, который содержит в себе путь к устройству, тип устройства и некий хэш.
Типов устройств выделено два (внутреннюю память я не стал трогать, так как к ней доступ можно получить через API системы).

И был создан класс StorageHelper, который и осуществляет поиск доступных карт памяти.

В классе StorageHelper реализовано два способа поиска — через системное окружение (Environment) и с использованием утилиты Linux mount, а точнее результата ее выполнения.

Способ первый — Environment

При работе с окружением я использую стандартную функцию getExternalStorageDirectory() для получения информации о внешней памяти. Чтобы получить информацию о удаляемой памяти, я использую переменную окружения «SECONDARY_STORAGE«.

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

Вариант решения взят со stackoverflow. Ответ где-то там внизу.

Способ второй — mount

Так как у меня долго не получалось заставить систему мне сказать путь к удаляемой памяти, я решил искать в сторону примонтированных устройств. В системе есть файлы конфигурации, в которых описаны правила монтирования внешних устройств. Все бы хорошо, но на Android версии 4.* к этому файлу простым смертным доступа нет, поэтому рассматривать этот способ не буду.

Вернемся к утилите mount. При запуске без параметров команда возвращает список смонтированных файловых систем. Удаляемые устройства имеют обычно формат файловой системы FAT, то будем выделять строки, в которых есть характеристика «fat«. Внешняя память будет характеризоваться параметром «fuse«.

Примечание: при использовании такого способа не всегда корректно (скорее всего я что-то не учел) определяются типы смотнтированных устройств. Разницу замечал на разных версиях Android. Поэтому этот способ можно использовать как дополнительный.

Вариант решения взят со stackoverflow. Ответов там несколько примерно одинаковых.

Про дублирование

Многие замечали в директории монтирования устройств такую картину:

И что самое интересно, все это одна и та же внешняя карта памяти. Такое дробление начинается с версии Jelly Bean и сделано это для поддержки многопользовательского режима работы системы. Более подробно тут. И вот, чтобы не получать одну и туже карту памяти как различные устройства, необходим способ определения идентичности. Если бы был доступ к конфигурации монтирования, то и вопросов не было. Но доступа нет. Поэтому я тут подсмотрел решение с расчетом хэша для каждого устройства:

  1. создаем StringBuilder
  2. записываем в него общий размер устройства и размер используемого пространства устройства
  3. обходим содержимое корня устройства
  4. записываем имя каталога
  5. записываем имя файла и размер
  6. вычисляем hash
Читайте также:  Webdav yandex настройка total commander android

Пример использования

Заключение

Подробные рассуждения по этому вопросу понимания памяти в Android, некоторые советы можно прочитать тут.

Исходный код всего класса расположен еще нигде не расположен. На днях постараюсь разместить на gitHub.

Источник

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.

Читайте также:  Kingroot для андроид как установить

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.

Источник

Android Storage: Internal, External, Removable. Часть 1/3

Всем, кто, несмотря ни на что, сумел сделать правильный выбор.

Это перевод серии статей от Mark Murphy из CommonsWare, широко известного на stackoverflow, а так же автора книг “The Busy Coder’s Guide to Android Development”, “Android’s Architecture Components”. Некоторые термины оставлены не переведенными специально.

Internal Storage

Существует много путаницы в отношении модели хранилища Android. Путаницы стало значительно больше с изменениями Android 4.4 в Storage Model, и с тех пор ситуация не улучшилась. Есть бесчисленное множество вопросов на Stack Overflow и тому подобных ресурсах, где люди явно не совсем разбираются в различных моделях хранилищ Android.

То, что пользователи считают Internal Storage

В зависимости от модели вашего устройства пользователи в конечном итоге придут в «Настройки» —> «Хранилище на этом устройстве» (Settings —> Storage on their device) или в эквивалентном месте, и могут видеть экран, который описывает «Внутреннее хранилище».

Пользователь думает, что вся встроенная флешка — это «внутреннее хранилище» (Internal Storage). К счастью, Google начал менять этот термин с Android 8.0, перейдя к «general storage» вместо «internal storage».

Тем не менее, пользователи могут по-прежнему видеть «внутреннее хранилище» в таких местах, как окно проводника в Windows, когда их устройство подключено через USB.

Что Google считает Internal Storage

Увы, то, что видят пользователи это не то же самое, что Android SDK считает «внутренним хранилищем», что приводит к некоторой путанице. Если вы читали документацию на Android по внутреннему хранилищу, то это описание … как минимум туманно (прим. текст изменился со времени написания статьи):

Вы можете сохранять файлы непосредственно во внутренней памяти устройства. По умолчанию файлы, сохраненные во внутреннем хранилище, являются приватными для вашего приложения, и другие приложения не могут получить к ним доступ (также как и пользователь). Когда пользователь удаляет приложение, эти файлы удаляются.

По правде говоря, Android SDK определяет «внутреннее хранилище» как особый каталог, уникальный для вашего приложения, где ваше приложение может размещать файлы. Как было предложено в документации, эти файлы по умолчанию предназначены для чтения и записи для вашего приложения и запрещены для любого другого приложения (исключение: пользователи, работающие с файловыми менеджерами с привилегиями суперпользователя на rooted устройствах могут получить доступ ко всему).

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

  • getCacheDir()
  • getDir()
  • getDatabasePath()
  • getFilesDir()
  • openFileInput()
  • openFileOutput()

Другие методы будут опираться на них, такие как openOrCreateDatabase() . Другие классы также будут полагаться на них, такие как SQLiteOpenHelper и SharedPreferences .

Где хранится Internal Storage … Иногда

Если вы просматриваете различные сообщения в блогах, ответы на StackOverflow и книги, выпущенные в 2012 году или ранее, вам сообщается, что «внутреннее хранилище» вашего приложения находится по адресу: /data/data/your.application.package.name .

Внутри будут некоторые каталоги, автоматически созданные Android, поскольку вы используете некоторые из методов Context. Например, getFilesDir() возвращает объект File , указывающий на каталог files/ во внутреннем хранилище вашего приложения.

Где хранится Internal Storage … Остальное время

Однако не всегда внутреннее хранилище вашего приложения находится в указанном месте. Для разработчиков есть одно правило, которое вы должны усвоить из этой серии сообщений в блоге, это:

NEVER HARDCODE PATHS.

Время от времени я вижу, что разработчики делают что-то вроде этого:

File f=new File(«/data/data/their.app.package.name/files/foo.txt»);

Это не преступление, это хуже, это — ошибка.

Правильный ход, да и писать меньше:

File f=new File(getFilesDir(), «foo.txt»);

Что еще более важно, внутреннее хранилище не всегда находится в одном месте. Примечательно, что у нас есть понятие отдельных профилей пользователей (separate user profiles), начиная с Android 4.2 для планшетов и Android 5.0 для телефонов. Каждый пользователь получает свое собственное «внутреннее хранилище». Хотя вышеупомянутый каталог по-прежнему используется для основного пользователя, не гарантируется, что он же будет использоваться для вторичных учетных записей.

Исследуем Internal Storage

Device File Explorer tool в Android Studio 3.0+ может просматривать все внутренние хранилища на эмуляторе, а также внутреннее хранилище отлаживаемых приложений на продакшн устройствах.

В командной строке вы можете использовать adb с опцией run-as .

Например, чтобы загрузить базу данных из внутреннего хранилища основного пользователя на вашу девелоперскую машину, вы можете использовать:

adb shell ‘run-as your.application.package.name cp /data/data/your.application.package.name/databases/dbname.db /sdcard’

Обратите внимание, что:

  • Вам нужно будет изменить пункт назначения туда, где на вашем устройстве монтируется внешнее хранилище (показано здесь как /sdcard/ , которое не будет одинаковым на всех устройствах)
  • Возможно, вам придется использовать cat вместо cp на старых устройствах
  • После того, как файл будет находиться на внешнем хранилище, вы сможете использовать adb pull , чтобы загрузить его на свой компьютер, или получить доступ к нему другими обычными способами (например, путем монтирования устройства в качестве диска).
Читайте также:  Как проверить технические характеристики смартфона андроид

Ограничения внутреннего хранилища

На старых устройствах Android 1.x и 2.x внутреннее хранилище обычно находилось в выделенном разделе файловой системы, и этот раздел обычно был довольно крошечным. HTC Dream (a.k.a., T-Mobile G1), оригинальное Android-устройство, обладал огромными 70 МБ встроенной памяти для использования всеми приложениями (это не опечатка, в то время мы измеряли память в мегабайтах).

К тому времени, когда вышли 2.3 устройства, внутреннее хранилище могло быть размером 1 ГБ.

Android 3.0 изменил модель хранилища, так как внутреннее хранилище стало больше объемом. У устройств, которые рекламируют как имеющее 4 ГБ, 8 ГБ, 16 ГБ и т.д. пространства для хранения, обычно имелось все это (минус существующее содержимое) доступное для внутреннего хранилища. Мы рассмотрим, что изменилось в Android 3.0 и его влияние на модель хранилища в следующих постах про внешнее хранилище.

Для Android 1.x и 2.x внутреннее хранилище было действительно только для небольших файлов, и вам нужно было использовать внешнее хранилище для всего остального. Android 3.0+ означает, что для большинства устройств и большинства пользователей внутреннее хранилище отлично подходит для файлов, которые не предназначены для обычного использования другими приложениями или доступны пользователю независимо от вашего приложения. Однако некоторые опытные пользователи обнаруживают, что даже on-board flash недостаточна для того, что они хотят хранить, поэтому они переходят на съемные хранилища… которые представляют собой банку с червями (прим. имеются в виду ἕλμινς) — источник многих непредсказуемых и сложных проблем.

F.A.Q. по Internal Storage

Должен ли я делать файлы во внутреннем хранилище World-Readable или World-Writeable?

О, $БОГИ, нет. Используйте FileProvider и обслуживайте этот контент с помощью реализации ContentProvider . После этого вы, по крайней мере, имеете возможность использовать систему разрешений Android для управления доступом к этим файлам, в отличие от вашего варианта, когда любое приложение в системе может испортить эти файлы.

Ну, а как насчет android:sharedUserId ?

android: sharedUserId — это атрибут, который вы можете поместить в манифест, который указывает логический идентификатор пользователя, который будет использоваться для вашего приложения. Любое другое приложение, которое установлено, которое подписывается одним и тем же ключом подписи и запрашивает тот же android:sharedUserId будет использовать одного и того же пользователя Linux с точки зрения безопасности. Эффект заключается в том, что эти два приложения смогут безнаказанно работать с файлами друг друга, так как эти файлы принадлежат одному и тому же пользователю Linux.

Этот атрибут реально предназначен для предварительно установленных приложений, таких как software suite предварительно загруженный производителем устройства, мобильным оператором или разработчиком модифицированной ROM прошивки. В частности, как только вы единожды установите свое приложение, вы не сможете затем безболезненно изменить свое значение android:sharedUserId не заблокировав при этом доступ пользователю к любым существующим файлам… поскольку Android не изменяет права владельца на существующие файлы при изменении учетной записи пользователя Linux, под которой запускается приложение.

Существуют различные риски при одновременном доступе нескольких процессов к файлам. Некоторые подсистемы, такие как SQLite, имеют встроенную логику для решения этой проблемы. Но если вы сами организуете свой собственный доступ к файлу (например, через File и Java I/O), вам нужно что-то делать с одновременным доступом, а это сложно.

Вам также нужно обрабатывать ситуацию, когда одно приложение деинсталлируется, удаляя файлы, которые использовало другое приложение. В модели hub-and-spoke, например, с приложением и набором плагинов, возможно, это не так рискованно. В других моделях, где приложения более равноправны, вы не можете позволить себе потерять данные своего приложения только потому, что пользователь решил удалить какое-то отдельное приложение.

Наконец, вы не знаете, что может принести будущее. Прямо сейчас вы можете рассматривать свой набор приложений в виде набора с тесной связью. Кто-то, кто приобретает эти приложения или приобретает вашу фирму, может пожелать пойти другим путем. Использование возможностей совместного доступа к данным, которые более слабо связаны, например ContentProvider , дает вам большую гибкость. В идеальном мире ваше приложение должно относиться к другим приложениям как к достаточно надежному, но не всегда доступному ресурсу, так же, как к вашему собственному веб-сервису.

Как запретить пользователям rooted устройств доступ к моим файлам во внутреннем хранилище?

Просто не помещайте файлы во внутреннее хранилище. Пользователи rooted устройств могут получить доступ к тому, что им нужно на устройстве, поэтому единственный способ предотвратить их доступ к вашим данным — не иметь их на устройстве.

Некоторые разработчики попытаются зашифровать свои файлы с помощью жестко запрограммированного пароля, чтобы пользователи rooted устройств не могли использовать эти файлы. Это создаст эффект «лежачего полицейского» на короткое время. Все, что требуется, — это один заинтересованный в реверс-инжиниринге вашего приложения человек, определивший, как расшифровать эти файлы, а затем написавший сообщение в блоге или форуме о том, как это сделать.

В целом, относительно мало людей с rooted устройствами — я оцениваю их на уровне менее 1%. ИМХО, вы преуспеете больше, сосредоточив свою инженерную работу на написании лучшего приложения, вместо того, чтобы тратить время на защиту от рутованных устройств.

Источник

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