Как я могу получить ответ «требуется разрешение на работу с SD-картой» при копировании на SD-карту — сообщество Android

Недавно, возможно, после установки Pie, я не мог копировать файлы на SD-карту из внутреннего хранилища или через локальную сеть с моего NAS из-за сообщения «требуется разрешение на работу с SD-картой», за которым следует страница с инструкциями, относящимися к меню которых нет на моем Moto X4. Огромным преимуществом Android перед iOS было то, что его файловая система была полностью доступна, как на ПК, что позволяло мне копировать и перемещать файлы во внутреннее хранилище и другие устройства. Я собираюсь отправиться в путешествие и хотел загрузить свои путевые документы, но не могу. Какая польза от внешней SD-карты, если я не могу писать на нее? Что ж, я могу писать из определенных приложений, но я хочу перемещать файлы с помощью файлового менеджера, как мы все делаем на наших компьютерах.

Это происходит со всеми тремя файловыми менеджерами, которые я пробовал: ES File Explorer, ASUS File Manager, File Manager Pro.


Универсальный способ записи на внешнюю SD-карту на Android

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

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

Как лучше предоставить доступ для чтения/записи к внешней SD-карте на разных уровнях API (Pre-KitKat, KitKat, Lollipop +)?

Обновление 1

Я попробовал метод 1 из ответа Doomknight, но безрезультатно: как вы можете видеть, я проверяю разрешения во время выполнения перед попыткой записи на SD:

  HashSet  extDirs = getStorageDirectories (); for (String dir: extDirs) {Log.e ("SD", dir);  Файл f = новый файл (новый файл (каталог), «TEST.TXT»);  попробуйте {если (ActivityCompat.checkSelfPermission (это, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {f.createNewFile ();  }} catch (IOException e) {e.printStackTrace ();  }}  

Но я получаю ошибку доступа, пробовал на двух разных устройствах: HTC10 и Shield K1.

  10-22  14: 52: 57.329 30280-30280/?  E/SD:/mnt/media_rw/F38E-14F810-22 14: 52: 57.329 30280-30280/?  W/System.err: java.io.IOException: ошибка открытия: EACCES (разрешение отказано) 10-22 14: 52: 57.329 30280-30280/?  W/System.err: в java.io.File.createNewFile (File.java:939) 10-22 14: 52: 57.329 30280-30280/?  W/System.err: в com.myapp.activities.TestActivity.onResume (TestActivity.java:167) 10-22 14: 52: 57.329 30280-30280/?  W/System.err: в android.app.Instrumentation.callActivityOnResume (Instrumentation.java:1326) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.Activity.performResume (Activity.java:6338) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.ActivityThread.performResumeActivity (ActivityThread. java: 3336) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.ActivityThread.handleResumeActivity (ActivityThread.java:3384) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2574) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.ActivityThread.access 900 долларов (ActivityThread.java:150) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1399) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.os.Handler.dispatchMessage (Handler.java:102) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.os.Looper.loop (Looper.java:168) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в android.app.ActivityThread.main (ActivityThread.java:5885) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в java.lang.reflect.Method.invoke (собственный метод) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:819) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в com.android.internal.os.ZygoteInit.main (ZygoteInit.java:709) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: вызвано: android.system.ErrnoException: ошибка открытия: EACCES (отказано в разрешении) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в libcore.io.Posix.open (собственный метод) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в libcore.io.BlockGuardOs.open (BlockGuardOs.java:186) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: в java.io.File.createNewFile (File.java:932) 10-22 14: 52: 57.330 30280-30280/?  W/System.err: ... еще 14  

Вы можете предоставить доступ для чтения/записи к внешней SD-карте на разных уровнях API (API23 + во время выполнения).

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

Универсальный способ:

История говорит, что не существует универсального способа записи на внешнюю SD-карту , но продолжается …

Этот факт демонстрируется этими примерами конфигураций внешнего хранилища для устройств.

Способ на основе API:

До KitKat попробуйте использовать метод Doomsknight 1, в противном случае метод 2.

Запросить разрешения в манифесте (Api = 23).

Рекомендуемый способ:

ContextCompat.getExternalFilesDirs решает ошибку доступа, когда вам не нужно делиться файлы.

Безопасный способ совместного использования — использовать поставщика контента или новую платформу доступа к хранилищу. .

Способ с учетом конфиденциальности:

Начиная с Android Q Beta 4, приложения, предназначенные для Android 9 (уровень API 28) или ниже не видят никаких изменений по умолчанию.

Приложения, ориентированные на Android Q по умолчанию (или выбирающие его), получают отфильтрованное представление во внешнем хранилище.


1. Первоначальный ответ.

Универсальный способ записи на внешнюю SD-карту на Android

Универсального способа записи на внешнюю SD-карту на Android не существует из-за постоянных изменений:

  • Pre-KitKat: официальная платформа Android вообще не поддерживает SD-карты, за исключением исключений.

  • KitKat: представил API-интерфейсы, которые позволяют приложениям получать доступ к файлам в каталогах приложений на SD-картах.

  • Lollipop: добавлены API-интерфейсы чтобы разрешить приложениям запрашивать доступ к папкам, принадлежащим другим поставщикам.

  • Nougat: предоставляет упрощенный API для доступа к общим каталогам внешнего хранилища.

  • … Изменение конфиденциальности Android Q: хранилище на уровне приложений и носителей

Как лучше предоставить доступ для чтения и записи к внешней SD-карте на разных уровнях API?

На основе моего и моего ответа Doomsknight, а также сообщений в блоге Дэйва Смита и Марка Мерфи: 1, 2, 3:

  • В идеале используйте Storage AccessF rameworkandDocumentFileas, на который указал Джаред Раммлер. Или:
  • Используйте путь к вашему приложению /storage/extSdCard/Android/data/com.myapp.example/files .
  • Добавьте разрешение на чтение/запись в манифест для pre-KitKat, разрешение не требуется позже для этого пути.
  • Попробуйте использовать путь к вашему приложению и методы Doomsknight, учитывая случай KitKat и Samsung.
  • Отфильтруйте и используйте getStorageDirectories, ваш путь к приложению и разрешения на чтение/запись до KitKat.
  • ContextCompat.getExternalFilesDirs, начиная с KitKat. Принимая во внимание устройства, которые сначала возвращают внутренние.

2. Обновленный ответ.

Обновление 1 . Я попробовал метод 1 из ответа Doomknight, но безрезультатно:

Как видите, я проверяю разрешения во время выполнения, прежде чем пытаться писать на SD …

Я бы использовал каталоги для конкретных приложений, чтобы избежать проблемы с вашим обновленным вопросом, и ContextCompat.getExternalFilesDirs () , используя документацию getExternalFilesDir в качестве ссылки.

Улучшите эвристику, чтобы определить, что представляет собой съемный носитель на основе различных уровней API, например android.os.Build.VERSION.SDK_INT> = android.os.Build.VERSION_CODES.KITKAT

… Но я получаю ошибку доступа, пробовал на двух разных устройствах: HTC10 и Shield K1.

Помните, что Android 6.0 поддерживает переносное хранилище устройства и сторонние приложения должны проходить через Storage Access Framework. Ваши устройства HTC10 и Shield K1, вероятно, относятся к API 23.

В вашем журнале показано исключение, запрещенное для доступа к /mnt/media_rw , как это исправление для API 19+:

     //эта строка добавлена ​​через root в ссылку, чтобы исправить это.  

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

Возможно, это альтернатива Gizm0 вашему методу getStorageDirectories () , это хорошая отправная точка.

ContextCompat.getExternalFilesDirs решает проблему, если вам не нужен доступ к другим папкам.


3. Android 1.0 .. Pre-KitKat.

До KitKat попробуйте использовать метод Doomsknight 1 или прочтите этот ответ Gnathonic.

  public static HashSet   getExternalMounts () {final HashSet  out = новый HashSet  ();  String reg = "(? I). * Vold. * (Vfat | ntfs | exfat | fat32 | ext3 | ext4). * Rw. *";  Строка s = "";  попробуйте {final Process process = new ProcessBuilder (). command ("mount") .redirectErrorStream (true) .start ();  process.waitFor ();  последний InputStream = process.getInputStream ();  последний байт [] буфер = новый байт [1024];  while (is.read (буфер)! = -1) {s = s + новая строка (буфер);  } закрыто();  } catch (последнее исключение e) {e.printStackTrace ();  }//анализируем вывод final String [] lines = s.split (" n");  for (String line: lines) {if (! line.toLowerCase (Locale.US) .contains ("asec")) {if (line.matches (reg)) {String [] parts = line.split ("")  ;  for (String part: parts) {if (part.startsWith ("/")) if (! part.toLowerCase (Locale.US) .contains ("vold")) out.add (part);  }}}} return out;}  

Добавьте следующий код в свой AndroidManifest.xml и прочтите Получение доступа к внешнему хранилищу

Доступ к внешнему хранилищу защищен различными разрешениями Android.

Начиная с Android 1.0, доступ на запись защищен кодом WRITE_EXTERNAL_STORAGE разрешение.

Начиная с Android 4.1, доступ для чтения защищен разрешением READ_EXTERNAL_STORAGE .

Чтобы … для записи файлов во внешнее хранилище ваше приложение должно получить … системные разрешения:

       

Если вам нужно и то, и другое …, вам необходимо запросите только разрешение WRITE_EXTERNAL_STORAGE .

Прочтите объяснение Марка Мерфи и рекомендуйте Дайан Хакборн и Дэйв Смит сообщений

  • До Android 4.4 не было официальной поддержки съемных носителей в Android. Начиная с KitKat, концепция «первичного» и «вторичного» внешнего хранилище появляется в FMW API.
  • Предыдущие приложения просто полагались на индексацию MediaStore, поставлялись с оборудованием или проверяли точки монтирования и применяли некоторые эвристические методы, чтобы определить, что представляет собой съемный носитель.

4. Android 4.4 KitKat представляет платформу доступа к хранилищу (SAF).

Игнорируйте следующее примечание из-за ошибок, но попробуйте использовать ContextCompat.getExternalFilesDirs () :

  • Начиная с Android 4.2, производители устройств запросили заблокировать съемные носители в целях безопасности (многопользовательская поддержка), и в 4.4.
  • Поскольку KitKat getExternalFilesDirs () и другие методы были добавлены для возврата пригодного пути для всех доступных томов хранилища (первый возвращаемый элемент — это первичный том) .
  • В таблице ниже показано, что разработчик может попытаться сделать и как KitKat отреагирует:

Примечание. Начиная с Android 4.4, эти разрешения не требуются, если вы читаете или записываете только файлы, которые являются личными для вашего приложения. Для получения дополнительной информации … см. Сохранение файлов, которые являются частными для приложения.

      

Также прочтите объяснение Паоло Ровелли и попробуйте использовать решение Джеффа Шарки с KitKat:

В KitKat теперь есть общедоступный API для взаимодействия с этими вторичными совместно используемыми запоминающими устройствами.

Новый Context.getExternalFilesDirs () и Context.getExternalCacheDirs () могут возвращать несколько путей, включая как первичные, так и вторичные устройства.

Затем вы можете перебирать их и проверять Environment.getStorageState () и File.getFreeSpace () , чтобы определить лучшее место для хранения ваших файлов.

Эти методы также доступны на ContextCompat в библиотеке support-v4.

Начиная с Android 4.4, владелец, группа и режимы файлов на экстенте Устройства хранения данных теперь синтезируются на основе структуры каталогов. Это позволяет приложениям управлять своими каталогами для конкретных пакетов на внешнем хранилище, не требуя, чтобы у них было широкое разрешение WRITE_EXTERNAL_STORAGE . Например, приложение с именем пакета com.example.foo теперь может свободно обращаться к Android/data/com.example.foo/ на внешних устройствах хранения с нет разрешений. Эти синтезированные разрешения достигаются путем обертывания необработанных устройств хранения в демоне FUSE.

С KitK ваши шансы на «полное решение» без рутирования практически равны нулю:

Здесь определенно облажался проект Android. Никакие приложения не получают полный доступ к внешним SD-картам:

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

Единственное место 3 сторонним приложениям rd разрешено писать на вашей внешней карте «свои собственные каталоги» (т.е. /sdcard/Android/data/ ).

Единственные способы действительно исправить, которые требуют либо производителя (некоторые из них исправили это, например, Huawei с их обновлением Kitkat для P6), либо root … (объяснение Иззи продолжается здесь)

цитата>


5. В Android 5.0 внесены изменения и вспомогательный класс DocumentFile.

getStorageState Добавлено в API 19, не рекомендуется в API 21, используйте getExternalStorageState (File)

Вот отличный учебник по взаимодействию с Storage Access Framework в KitKat.

Взаимодействие с новыми API в Lollipop очень похоже (Объяснение Джеффа Шарки).


6. Android 6.0 Marshmallow представляет новую модель разрешений во время выполнения.

Запросить разрешения во время выполнения, если уровень API 23+, и прочтите «Запрос разрешений во время выполнения»

Начиная с Android 6.0 (уровень API 23), пользователи предоставляют разрешения приложениям во время работы приложения, а не во время установки приложения … или обновления приложения … пользователь может отозвать разрешения .

 //Предположим, thisActivity является текущим разрешением activityintCheck = ContextCompat.checkSelfPermission (thisActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE);  

Android 6.0 представляет новую модель разрешений во время выполнения, в которой приложения запрашивают возможности при необходимости во время выполнения. Поскольку новая модель включает разрешения READ/WRITE_EXTERNAL_STORAGE , платформе необходимо динамически предоставлять доступ к хранилищу без отключения или перезапуска уже запущенных приложений. Это достигается за счет поддержки трех различных представлений всех подключенных устройств хранения:

  • /mnt/runtime/default отображается для приложений без специальных разрешений на хранение …
  • /mnt/runtime/read отображается для приложений с READ_EXTERNAL_STORAGE
  • /mnt/runtime/write отображается для приложений с WRITE_EXTERNAL_STORAGE

7. Android 7.0 предоставляет упрощенный API для доступа к каталогам внешнего хранилища.

Доступ к каталогам с заданной областью В Android 7.0 приложения могут использовать новые API-интерфейсы для запроса доступа к определенным каталогам внешнего хранилища, включая каталоги на съемные носители, такие как SD-карты …

Для получения дополнительной информации см. обучение по доступу к каталогу с ограничением.

Прочтите сообщения Марка Мерфи: будьте осторожны с Ограниченный доступ к каталогу. Он был объявлен устаревшим в Android Q:

Обратите внимание , что доступ к каталогу с ограниченным доступом, добавленный в 7.0, не рекомендуется в Android Q.

В частности, метод createAccessIntent () в StorageVolume устарел.

Они добавили createOpenDocumentTreeIntent () , который можно использовать в качестве альтернативы.


8. Android 8.0 Oreo .. Изменения в бета-версии Android Q

Начиная с Android O, Storage Access Framework позволяет поставщикам настраиваемых документов создавать файловые дескрипторы с возможностью поиска для файлов, находящихся в удаленном источнике данных …

Разрешения, до Android O , если приложение запрашивало разрешение во время выполнения и разрешение было предоставлено, система также неверно предоставила приложению остальные разрешения, которые принадлежали той же группе разрешений и были зарегистрированы в манифесте.

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

Например, READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE

Обновление: более ранняя бета-версия Android Q временно заменила READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE с более детализированными разрешениями для конкретных носителей.

Примечание. Google ввел роли в бета-версии 1 и удалили их из документации перед бета-версией 2 …

Примечание. Особые разрешения для коллекций мультимедиа, которые были представлены в более ранних версиях бета-версии — READ_MEDIA_IMAGES , READ_MEDIA_AUDIO и READ_MEDIA_VIDEO — теперь устарели. Подробнее:

Обзор Q Beta 4 (финальные API) от Марка Мерфи: Смерть внешнего хранилища: Конец саги (?)

«Смерть универсальнее жизни. Все умирают, но не все живут». — Эндрю Сакс


9. Связанные вопросы и рекомендуемые ответы.

Как я могу получить путь к внешней SD-карте для Android 4.0+?

mkdir () работает внутри внутренней флэш-памяти, но не SD card?

Разница между getExternalFilesDir и getExternalStorageDirectory ()

Почему getExternalFilesDirs () не работает на некоторых устройствах?

Как сделать используйте новый API доступа к SD-карте, представленный для Android 5.0 (Lollipop)

Запись на внешнюю SD-карту в Android 5.0 и выше

Разрешение на запись на SD-карту Android с использованием SAF ( Структура доступа к хранилищу)

SAFFAQ: FAQ по структуре доступа к хранилищу


10. Связанные ошибки и проблемы.

Ошибка: на Android 6 при использовании getExternalFilesDirs он не позволял создавать новые файлы в его результатах

Запись в каталог, возвращаемый getExternalCacheDir () на Lollipop не работает без разрешения на запись


Я считаю, что есть два способа добиться этого:

СПОСОБ 1: (не НЕ работает на 6.0 и более поздних версиях из-за изменений разрешений)

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

Он вернет все подключенные носители (включая Real SD Карты) в списке расположений каталога строк. С помощью списка вы можете затем спросить пользователя, где сохранить и т. Д.

Вы можете вызвать его следующим образом:

  HashSet   extDirs = getStorageDirectories ();  

Метод:

 /** * Возвращает все возможные каталоги SDCard */public static HashSet   getStorageDirectories () {final HashSet  out = new HashSet  ();  String reg = "(? I). * Vold. * (Vfat | ntfs | exfat | fat32 | ext3 | ext4). * Rw. *";  Строка s = "";  попробуйте {final Process process = new ProcessBuilder (). command ("mount") .redirectErrorStream (true) .start ();  process.waitFor ();  последний InputStream = process.getInputStream ();  последний байт [] буфер = новый байт [1024];  while (is.read (буфер)! = -1) {s = s + новая строка (буфер);  } закрыто();  } catch (последнее исключение e) {e.printStackTrace ();  }//анализируем вывод final String [] lines = s.split (" n");  for (String line: lines) {if (! line.toLowerCase (). contains ("asec")) {if (line.matches (reg)) {String [] parts = line.split ("");  for (String part: parts) {if (part.startsWith ("/")) if (! part.toLowerCase (). contains ("vold")) out.add (часть);  }}}} return out;}  

СПОСОБ 2:

Используйте библиотеку поддержки v4

  import android.support.v4.content.ContextCompat;  

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

  File [] list = ContextCompat.getExternalFilesDirs (myContext, null);  

однако местоположения различаются по использованию.

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

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

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

Подробнее о ContextCompat

Они похожи на конкретные приложения файлы. Скрыто от других приложений.

21


Еще один ответ . Этот ответ показывает только 5.0+, потому что я считаю, что опубликованный здесь ответ Doomknight — лучший способ сделать это для Android 4.4 и ниже.

Первоначально он опубликован здесь (есть ли способ получить размер SD-карты в Android?), Чтобы получить размер внешней SD-карты на Android 5.0+

Чтобы получить внешнюю SD-карту в виде файла :

  public File getExternalSdCard () {File externalStorage = null;  if (Build.VERSION.SDK_INT> = Build.VERSION_CODES.LOLLIPOP) {Хранилище файлов = новый файл ("/хранилище");  if (storage.exists ()) {Файл [] files = storage.listFiles ();  для (файл файл: файлы) {если (файл.exists ()) {попробуйте {если (Environment.isExternalStorageRemovable (файл)) {externalStorage = файл;  перерыв;  }} catch (Exception e) {Log.e ("TAG", e.toString ());  }}}}} else {//выполняем один из многих старых методов//я считаю, что метод Doomsknight - лучший вариант} return externalStorage;}  

Примечание: я получаю только «первая» внешняя SD-карта, однако вы можете изменить ее и вернуть ArrayList вместо File и позволить циклу продолжаться вместо вызова прервать после того, как будет найден первый.

3


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

Первый ресурс взят из Android Programming, The Big Nerd Ranch Guide 2nd edition , глава 16, стр. 294.

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

Следующая часть из книги:

Внешнее хранилище

Вашей фотографии нужно больше, чем просто место на экране. Полноразмерные изображения слишком велики, чтобы их можно было вставить в базу данных SQLite, не говоря уже о Intent . Им понадобится место для размещения в файловой системе вашего устройства. Как правило, вы должны поместить их в свое личное хранилище. Напомним, что вы использовали свое частное хранилище для сохранения базы данных SQLite. С помощью таких методов, как Context.getFileStreamPath (String) и Context. getFilesDir () , вы можете сделать то же самое и с обычными файлами (которые будут находиться в подпапке рядом с подпапкой базы данных, в которой находится ваша база данных SQLite)

Основные методы файлов и каталогов в

  |  Метод || -----------------------------------------------  ---------------------------------------- || Файл getFilesDir () ||  - Возвращает дескриптор каталога для личных файлов приложения.  ||  || FileInputStream openFileInput (имя строки) ||  - Открывает существующий файл для ввода (относительно каталога файлов).  ||  || FileOutputStream openFileOutput (имя строки, режим int) ||  - Открывает файл для вывода, возможно, создавая его (относительно каталога файлов).  ||  || Файл getDir (String name, int mode) ||  - Получает (и, возможно, создает) подкаталог в каталоге файлов.  ||  || String [] fileList () ||  - Получает список имен файлов в основном каталоге файлов, например, для использования с ||  openFileInput (строка).  ||  || Файл getCacheDir () ||  - Возвращает дескриптор каталога, который вы можете использовать специально для хранения файлов кеша.  ||  Вы должны позаботиться о том, чтобы этот каталог был аккуратным и использовал как можно меньше места |  

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

С другой стороны, если вам нужно другое приложение для записи в эти файлы, вам не повезло: пока есть флаг Context.MODE_WORLD_READABLE , вы можете передать в openFileOutput (String, int) , он устарел и не полностью надежен в своих эффектах на новых устройствах. Если вы храните файлы для совместного использования с другими приложениями или получаете файлы из других приложений (файлы, например, сохраненные изображения), вам необходимо вместо этого хранить их во внешнем хранилище.

Существует два типа внешнего хранилища: основное, и все остальное. Все устройства Android имеют по крайней мере одно расположение для внешнего хранилища: основное расположение, которое находится в папке, возвращаемой Environment.getExternalStorageDirectory () . Это может быть SD-карта, но в настоящее время она чаще интегрируется в само устройство. Некоторые устройства могут иметь дополнительное внешнее хранилище. Это подпадает под «все остальное».

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

Методы внешних файлов и каталогов в

  |  Метод ||  --------------------------------------------------  ------------------------------------ || Файл getExternalCacheDir () ||  - Возвращает дескриптор папки кэша в основном внешнем хранилище.  Относитесь к нему как к себе ||  getCacheDir (), за исключением более тщательной.  Android еще реже очищается ||  вверх по этой папке, чем в частном хранилище. ||  || Файл [] getExternalCacheDirs () ||  - Возвращает папки кеша для нескольких внешних хранилищ.  ||  || Файл getExternalFilesDir (String) ||  - Возвращает дескриптор папки на первичном внешнем хранилище, в которой следует хранить обычный ||  файлы.  Если вы передадите тип String, вы получите доступ к определенной подпапке, выделенной ||  к определенному типу контента.  Константы типа определены в Environment, где ||  они имеют префикс DIRECTORY_.  ||  Например, изображения идут в Environment.DIRECTORY_PICTURES.  ||  || Файл [] getExternalFilesDirs (String) ||  - То же, что и getExternalFilesDir (String), но возвращает все возможные папки с файлами для ||  данный тип.  ||  || Файл [] getExternalMediaDirs () ||  - Возвращает дескрипторы всех внешних папок, которые Android делает доступными для хранения ||  медиа - картинки, фильмы и музыка.  Чем это отличается от вызова ||  getExternalFilesDir (Environment.DIRECTORY_PICTURES) заключается в том, что медиа-сканер ||  автоматически сканирует эту папку.  Медиа-сканер делает файлы доступными для ||  приложения, которые проигрывают музыку или просматривают фильмы и фотографии, так что все, что вы ||  помещенный в папку, возвращенную функцией getExternalMediaDirs (), автоматически появится в ||  эти приложения.  |  

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

Разрешение на внешнее хранилище

В общем, вам нужно разрешение на запись или чтение из внешнего хранилища. Разрешения — это хорошо известные строковые значения, которые вы вводите в свой манифест с помощью тега . Они говорят Android, что вы хотите сделать что-то, на что Android хочет, чтобы вы попросили разрешения.

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

В Android 4.4, KitKat это ограничение было снято. Поскольку Context.getExternalFilesDir (String) возвращает папку, специфичную для вашего приложения, логично, что вы захотите иметь возможность читать и записывать файлы, которые там находятся. Таким образом, на Android 4.4 (API 19) и выше вам не нужно это разрешение для этой папки. (Но он все еще нужен для других видов внешнего хранилища.)

Добавьте в свой манифест строку, которая запрашивает разрешение на чтение внешнего хранилища, но только до Листинга 16.5 API Запрос разрешения внешнего хранилища ( AndroidManifest. xml )

     

Атрибут maxSdkVersion позволяет app запрашивает это разрешение только в версиях Android, которые старше API 19, Android KitKat. Обратите внимание, что вы запрашиваете только чтение внешнего хранилища. Также есть разрешение WRITE_EXTERNAL_STORAGE , но оно вам не нужно. Вы не будете ничего записывать во внешнее хранилище: приложение камеры сделает это за вас

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

Ссылка:

  • Параметры хранилища Android: https://developer.android.com/guide/topics/data/data-storage.html
  • Сайт книги: https://www.bignerdranch.com/we-write/android-programming

Дополнительные материалы для чтения:

  • https://developer.android.com/reference/android /os/Environment.html#getExternalStoragePublicDirectory%28java.lang.String%29
  • https://developer.android.com/reference/android/os/Environment.html#DIRECTORY_PICTURES
  • https://developer.android.com/reference/android/os/Environment.html#DIRECTORY_MOVIES
  • Как я могу получить путь к внешней SD-карте для Android 4.0 +?

Отказ от ответственности: Эта информация была взята из Android Pr программирование: The Big Nerd Ranch Guide с разрешения авторов. Чтобы получить дополнительную информацию об этой книге или приобрести копию, посетите сайт bignerdranch.com.


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

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

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

 //Примечание: FileSystemDevice - это просто мой собственный класс-оболочка.  Не стесняйтесь заменить его своим.  частный список  getDevices () {Список  устройств = новый ArrayList  (); //Добавляем внешнее хранилище по умолчанию, если доступно.  Файл sdCardFromSystem = null;  переключатель (Environment.getExternalStorageState ()) {case Environment.MEDIA_MOUNTED: case Environment.MEDIA_MOUNTED_READ_ONLY: case Environment.MEDIA_SHARED: sdCardFromSystem = Environment.getExternalStorageDirectory ();  перерыв;  } if (sdCardFromSystem! = null) {устройства. добавить (новый FileSystemDevice (sdCardFromSystem));  }//Читаем/proc/mounts и добавляем все точки монтирования, которые//доступны и не являются "специальными".  Также проверьте, не содержится ли//внешнее хранилище по умолчанию внутри точки монтирования.  попробуйте {FileInputStream fs = new FileInputStream ("/proc/mounts");  Строка mounts = IOUtils.toString (fs, «UTF-8»);  for (Строка строки: mounts.split (" n")) {Строка [] parts = line.split (""); //parts [0] - тип монтирования//parts [1] - точка монтирования if (parts.length> 1) {try {//Пропускать «специальные» точки монтирования и точки монтирования, к которым можно получить доступ//напрямую с помощью функций Android  .  если (части [0] .equals ("proc")) {продолжить;  } если (части [0] .equals ("rootfs")) {продолжить;  } if (parts [0] .equals ("devpts")) {продолжить;  } if (parts [0] .equals ("none")) {продолжить;  } если (части [0] .equals ("sysfs")) {продолжить;  } если (части [0] .equals ("selinuxfs")) {продолжить;  } если (parts [0] .equals ("debugfs")) {продолжить;  } если (части [0] .equals ("tmpfs")) {продолжить;  } если (части [1] .equals (Environment.getRootDirectory (). getAbsolutePath ())) {продолжить;  } если (части [1] .equals (Environment.getDataDirectory (). getAbsolutePath ())) {продолжить;  } если (части [1] .equals (Environment.getExternalStorageDirectory (). getAbsolutePath ())) {продолжить;  }//Убедитесь, что точка монтирования доступна, перечислив ее содержимое.  Файл файл = новый файл (части [1]);  if (file.listFiles ()! = null) {try {//Получить канонический путь на случай, если это просто символическая ссылка на другую точку монтирования.  String devPath = file.getCanonicalPath ();  для (устройство FileSystemDevice: устройства) {if (! devices.contains (devPath)) {devices.add (new FileSystemDevice (new File (devPath)));  }}} catch (Exception e) {//Тихо пропустить исключение, так как оно может возникнуть только в том случае, если точка монтирования недействительна.  e.printStackTrace ();  }}} catch (Exception e) {//Тихо пропустить исключение, так как оно может возникнуть только в том случае, если точка монтирования недействительна.  e.printStackTrace ();  }}} fs.close ();  } catch (FileNotFoundException e) {//Тихо пропустить исключение, так как оно может возникнуть только в том случае, если файл/proc/mounts недоступен. //Возможно, здесь можно вызвать другой метод обнаружения.  e.printStackTrace ();  } catch (IOException e) {//Тихо пропустить исключение, поскольку оно может возникнуть только в том случае, если файл/proc/mounts недоступен. //Возможно, здесь можно вызвать другой метод обнаружения.  e.printStackTrace ();  } вернуть устройства;}  


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

  попробуйте {File dir = new File (Environment.getExternalStorageDirectory () + "/foldername/");  если (! dir.exists ()) {dir.mkdirs ();  } Файл sdCardFile = новый файл (Environment.getExternalStorageDirectory () + "/foldername/" + fileName);  int num = 1;  Строка fileNameAux = fileName;  в то время как (sdCardFile.exists ()) {fileNameAux = fileName + "_" + num;  sdCardFile = новый файл (Environment.getExternalStorageDirectory () + "/имя папки/" + имя_файлаAux);  число ++;  }  

Это также контролирует существование файла и добавляет число в конце имени нового файла, чтобы сохранить его.

Надеюсь, это поможет !

РЕДАКТИРОВАТЬ: Извините, я забыл, что вы должны запросить в своем манифесте (или программно, если вы предпочитаете Marshmallow)

Оцените статью
clickpad.ru
Добавить комментарий