Android content url to file

Android Content URI: How to Get the File URI

In this blog post we are going to look at how we can pick file in Android without messing with Content URI. If you are just beginning with Android. You will notice that you will get a content:// URI after you do Intent.ACTION_OPEN_DOCUMENT . But this URI is useless if you want to lets say send file to server. To overcome this you have to either use a file picker library or manually check each type and try to get the actual location.

But there’s actually another much more easier and efficient way of doing this. But every way it has it’s disadvantages. We will look at it one by one. I’ll list when it might not be idle to use this approach.

Introduction to Storage Access Framework ( SAF )

Storage Access Framework or SAF is a newer approach to accessing the files in Android device. Not only local files but you can also access the online storage provider such as Google Drive.

It is an easy and centralized way to access everything in your device from multiple providers. Let us look at the image below.

Taken from Documentation

We have client that can either create or access the existing file from any one of the listed providers after doing Intent.ACTION_OPEN_DOCUMENT or Intent.ACTION_CREATE_DOCUMENT . We will be only looking at opening files in this post.

But SAF comes with its own challenge of not exposing the actual URI. Which is very good from security perspective as it limits the interactions. But how do we get the file to upload it somewhere or do something with it withing our own application ?

This post will exactly do that. We will pick file in Android and not worry about the Content URI. Let us quickly see what we are going to do before we actually do anything.

Our strategy to using SAF

Let us see what we can do to use SAF. We will follow the following steps to utilizing the framework.

  1. Open the system’s document picker
  2. Get the Content URI for the selected file(s)
  3. Copy the contents of file to cache directory
  4. Use the cached version of the file
  5. Clear the cache after the operation completes

Those are the steps to using the SAF. We will be following the listed approach to accomplish the task.

Limitations and disadvantages of this approach

It might not be ideal to always use this approach specially because we will be caching a copy to be used locally by our application.

Which will quickly grow the applications cache size. But if you think this will not be an issue with your current project. Then you can use it without any side effects at all.

Also this approach will not work if you want to directly modify the source file rather than a locally cached version. But it’s worth noting that this approach will download the file from remote server which might be advantageous in certain cases.

I was using this approach because I had to send some data via Rest API to remote server. Let us begin.

Opening system’s file picker

We can open the system’s UI for picking the document. Where we can either pick a single file or pick multiple files. We will look at both approaches. There is only a slight difference in picking a single file or multiple file.

Читайте также:  Стартовая страница яндекс установить андроид автоматически

We have this object which will help us show a system document picker. Briefly explained below.

showPicker method will show the picker UI and the result will be passed on to onActivityResult from the Activity or Fragment ‘s onActivityResult .

If you look closely you will see that there is OnActionComplete interface which has methods that will be invoked after the completion of the specific action.

But how will you use the above object ? See this snippet for showing the file picker

And for handling the result pass it from the onActivityResult callback.

We have successfully completed the selection action. Let us look at how we can copy the file locally in cache.

Caching the file from the URI

Look at this class named FileCache which has all the required methods to copy files from content:// URI.

It shouldn’t be too hard to understand what’s going on as I have commented major portions of the code.

This code will copy all the files from source to app’s mContext.cacheDir which can be queried later by listing files from there.

Let us finally see how we can combine everything in our MainActivity.

Wrapping everything up

Now that we have completed major portions of the code. Let us see how we can actually use it in our MainActivity .

The code for the design activity_main.xml .

And our final MainActivity looks like

Now that is all that we had to do. Everything should be available in the cache directory of the application.

What do you think about this approach to getting android content from content URI without converting it to file URI ?

Источник

Преобразование файла: Uri в файл в Android

какой самый простой способ конвертировать из file: android.net.Uri до File В Android?

пробовал следующее, Но это не работает:

15 ответов

то, что вы хотите.

Примечание: uri.toString() возвращает строку в формате: «file:///mnt/sdcard/myPicture.jpg» , тогда как uri.getPath() возвращает строку в формате: «/mnt/sdcard/myPicture.jpg» .

после долгого поиска это то, что сработало для меня:

EDIT: Извините, я должен был протестировать лучше раньше. Это должно сработать:

ничего из этого не работает для меня. Я нашел это рабочим решением. но мой случай специфичен для изображений.

непосредственно и скопируйте файл. См. также:

С Котлином еще проще:

Я сделал это следующим образом:

поэтому в основном сначала я пытаюсь использовать файл, т. е. снимок, сделанный камерой и сохраненный на SD-карте. Это не работает для изображения возвращаемых: Intent photoPickerIntent = новое намерение(намерение.ACTION_PICK); В этом случае необходимо преобразовать Uri в реальный путь по

@CommonsWare объяснил все вещи довольно хорошо. И мы действительно должны использовать предложенное им решение.

кстати, только на информацию мы могли положиться, когда quering ContentResolver — Это имя и размер файла, как указано здесь: получение информации о файле / разработчики Android

как вы могли видеть, есть интерфейс OpenableColumns который содержит только два поля: DISPLAY_NAME и SIZE.

в моем случае мне нужно было получить информацию EXIF о JPEG изображение и повернуть его, если это необходимо перед отправкой на сервер. Для этого я скопировал содержимое файла во временный файл с помощью ContentResolver и openInputStream()

Лучшим Решением

создайте один простой класс java FileUtil и используйте для создания, копирования и переименования файла

Я использую uri.toString() и uri.getPath() но не работает для меня. Я наконец нашел решение.

пользовательский класс FileUtil в вашем коде

вы можете получить файл из файла Uri, используя следующий метод. Он DocumentFile для параметра, но вы можете легко изменить его. Самый простой способ проверить этот метод для создания файла uri с помощью DocumentFile.fromFile(Environment.getExternalStorageDirectory()); который имеет Uri file:///storage/emulated/0

вместо создания файлов из Uri используйте DocumentFile.fromTreeUri(Context, Uri) или DocumentFile.fromSingleri(Context, Uri) для создания или удаления файлов и для потоков используйте getContentResolver().openOutputStream(documentFile.getUri()) и getContentResolver().openInputStream(documentFile.getUri()) для записи файлов и чтения файлов.

публичная строка getRealPathFromURI(Uri uri) <

затем, используя для получения файла из URI:

Читайте также:  Jikage rising андроид русификатор

— НАДЕЖДА МОЖЕТ ПОМОЧЬ ВАМ — — — —

Android + Котлин

добавить зависимость для расширений Kotlin Android:

получить файл из uri:

Android + Java

просто переместить наверх 😉

следующим кодом я могу получить общий pdf-файл adobe application в виде потока и сохранить его в путь приложения android

для людей, которые ищут решение для изображений в частности вот это.

Источник

Как использовать содержимое из Uri

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

Посмотрим на такую ситуацию со стороны потребителя: вам передают Uri с каким-нибудь контентом в случае, когда раньше вы ожидали путь к файлу. Как вы будете получать этот контент?

Что можно делать?

Во-первых, убедитесь, что в любом месте, где у вас есть для схемы file, у вас также есть для content, с областью видимости для соответствующего MIME типа. Вы можете получить контент Uri другими способами (например, в onActivityResult()), но если вы поддерживаете файл-подобный контент для таких действий, как ACTION_VIEW, убедитесь, что вы поддерживаете как file, так и content Uri.

Следующим шагом поймите, какую роль играет Uri. Некоторые значения Uri указывают на записи базы данных, например, если вы предлагаете пользователю выбрать контакт. Такие случаи в данный момент нам неинтересны. Другие значения указывают на вещи, которые могут какими-то файлами — вот для этого мы и нужна эта статья.

Затем, если Uri имеет схему content, вы можете сделать следующее с экземпляром ContentResolver:

  • Вызовите openInputStream() для чтения контента.
  • Вызовите getType(), чтобы получить тип MIME данных.
  • Вызовите query(), запрашивающий OpenableColumns, в котором вы сможете получить размер контента и некоторую разновидность отображаемого имени, связанного с контентом.

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

И это, в общем-то, всё.

Чего не стоит делать?

К сожалению, хотя и не всем нравится эти решение, но многие думают, что это единственный подходящий вариант.

Просто забрать путь

Некоторые разработчики вызывают getPath() у Uri, а затем пытаются открыть его как файл (например, new File(uri.getPath())).

Не делайте так!

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

Если у Uri есть какая-либо другая схема, например content, путь в значительной мере становится бесполезным для вас.

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

Представить, что MediaStore знает, чего вы хотите

Некоторые разработчики пытаются запросить MediaStore для столбца DATA в надежде, что они смогут конвертировать Uri в путь к файлу.

Не делайте так!

Не каждый content Uri поступает из MediaStore. На самом деле, в настоящее время относительно немногие Uri так делают. MediaStore ничего не знает о значениях Uri от других поставщиков. Кроме того, даже если вы получите MediaStore Uri, который может индексировать медиа на съёмном носителе, у вас не будет доступа к файловой системе.

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

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

Не делайте так!

Тот факт, что это возможно, является частичной ошибкой Google, поскольку они не сделали значения Uri более скрытыми.

Однако, этот способ тоже ненадёжен:

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

Ниже представлен список вопрос, которые могут возникнуть в данной ситуации.

Как получить имя файла?

Вы не можете этого сделать.

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

Читайте также:  Как изменить имя оператора андроид

DISPLAY_NAME, который вы можете получить из вышеупомянутого OpenableColumns, может быть именем файла, но также может и не быть. Термин «отображаемое имя» необязательно означает имя файла.

Кроме того, в зависимости от того, откуда контент идёт, фактически никакого файла может не существовать. Предположим. что кто-то в заметку с длинной записью в приложении для заметок, и это приложение делает её доступной через Uri для доступа к другим приложениям. Пользователь не создавал файл, не загружал, не делал ничего, связанного с файлами, с этой заметкой. Даже если для неё есть подлинное имя файла, оно не будет иметь никакого значения для пользователя.

Хорошо, тогда как мне получить расширение файла?

Вы не можете этого сделать.

Ещё раз, вы можете узнать, заканчивается ли Uri тем, что выглядит как имя файла. Нет никакого гарантии, что что-то вроде foo.bar будет являться файлом с расширением .bar.

Вы можете использовать MimeTypeMap или аналогичные виды преобразователей, чтобы попытаться получить MIME тип, который вы получаете из getType(), и затем получить расширение файла. Однако эти конвертеры обрабатывают только популярные MIME типы и не могут обработать кастомные.

Что делать, если мне нужно передать файл в библиотеку?

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

Затем, рассмотрите замену библиотеку на ту, которая имеет вариант InputStream.

Наконец, создайте локальную копию контента, получив InputStream из ContentResolver, подучив FileOutputStream в локальном файле (например, внутри getCacheDir() для внутреннего хранилища) и используя операции ввода-вывода для копирования из InputStream в OutputStream. flush(), getFD.sync() и close() FileOutputStream, и теперь у вас есть файл. который вы можете передать в библиотеку.

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

Как долго я могу использовать Uri?

Предполагая, что на стороне провайдера ничего не происходит, Uri должен быть действителен в течение всего процесса, но после этого он может стать недействительным.

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

Но что делать, если мне понадобится контент на более длительное время?

Вы можете вызвать takePersistableUriPermission() в ContentResolver. Если провайдер предлагает удержать разрешения, и вы их принимаете, то система запомнит, что у вас есть доступ к Uri. Соблюдайте осторожность, вы можете использовать метод для неограниченного доступа к контенту бескончно или до тех пор, пока пользователь не переместит, удалит или сделает недоступным к контенту по старому Uri.

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

Другой вариант — сделать локальную копию, как было отмечено ранее в FAQ. Таким образом вы сможете контролировать свою копию. Это может потребовать некоторой корректировки вашего UI и терминологии. Вместо использования глаголов типа «перейти» (предполагая, что контент находится в другом месте), используйте «импортировать», «копировать», чтобы подчеркнуть тот факт, что содержимое копируется. Вы можете предложить функции «обновить», «заменить», чтобы пользователь смог получить свежий Uri, который вы можете использовать, чтобы заменить существующую локальную копию новой.

Зачем столько боли?

Видение Google заключается в том, что значения content Uri являются эквивалентом Android http / https в веб-приложениях: универсально понятные и используемые. В конце концов, ContentResolver может сделать этот контент доступным из:

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

Использование значений content Uri намного более гибкое и предлагает больше различных параметров безопасности.

Источник

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