- Преобразование файла: Uri в файл в Android
- 15 ответов
- Get File Path From URI in Android JAVA
- Utility Class to Get File Path From URI in Android
- How to use UriUtils class
- Как использовать содержимое из Uri
- Что можно делать?
- Чего не стоит делать?
- Просто забрать путь
- Представить, что MediaStore знает, чего вы хотите
- Попробовать извлечь путь
- Как получить имя файла?
- Хорошо, тогда как мне получить расширение файла?
- Что делать, если мне нужно передать файл в библиотеку?
- Как долго я могу использовать Uri?
- Но что делать, если мне понадобится контент на более длительное время?
- Зачем столько боли?
- Реализация File Picker в Android и копирование выбранного файла в другое место
- EDIT (текущий код)
- EDIT с кодом, работающим благодаря @YS , @Lukas Knuth и @CommonsWare .
Преобразование файла: 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:
— НАДЕЖДА МОЖЕТ ПОМОЧЬ ВАМ — — — —
Android + Котлин
добавить зависимость для расширений Kotlin Android:
получить файл из uri:
Android + Java
просто переместить наверх 😉
следующим кодом я могу получить общий pdf-файл adobe application в виде потока и сохранить его в путь приложения android
для людей, которые ищут решение для изображений в частности вот это.
Источник
Get File Path From URI in Android JAVA
In Android when we pick an image, video, or any other type of file from the gallery, documents folder, or capture directly from the camera, we receive a URI object in intent. We have different ways to get a full file path from URI based on content providers. In this article, we will discuss how to get a file path from URI in Android for the coming files picked through Storage, Documents, as well as depending upon the _data field for the MediaStore and other file-based ContentProviders.
Following is the Java code if you are looking for Kotlin solution visit this Get Path From URI In Kotlin.
Utility Class to Get File Path From URI in Android
Create a file UriUtils.java and copy the following class in that file.
How to use UriUtils class
You might think that this class is too lengthy, but as mentioned above it handles all scenarios. It checks all android versions and the folders to what the Uri is appointing. It handles different types of content providers. There are different methods depending upon documents path, is it coming through downloads folder or media directory. It also checks is it picked through SECONDARY_STORAGE or EXTERNAL_STORAGE. Few other scenarios like Google Photos Uri, Google drive Uri are also handled properly. Just copy this class in your project as a utility class and rest will be handled by it.
That’s it. This is how to get file path from URI in Java 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 намного более гибкое и предлагает больше различных параметров безопасности.
Источник
Реализация File Picker в Android и копирование выбранного файла в другое место
Я пытаюсь реализовать File Picker в своем проекте Android. То, что я смог сделать до сих пор:
И затем в моем onActivityResult()
Это открывает сборщик файлов, но это не то, что я хочу. Например, я хочу выбрать файл (.txt), а затем получить этот File а затем использовать его. С помощью этого кода я думал, что получаю полный путь, но этого не произойдет; Например, я получаю: /document/5318/ . Но с этим путем я не могу получить файл. Я создал метод PathToFile() который возвращает File :
То, что я пытаюсь сделать, это позволить пользователю выбрать File из любого места – DropBox , Drive , SDCard , Mega и т. Д. И я не нашел способ сделать это правильно, я попытался получить Path затем File по этому Path … но он не работает, поэтому я думаю, что лучше получить сам File , а затем с помощью этого File программным путем Copy это или Delete .
EDIT (текущий код)
Там у меня вопрос, потому что я не знаю, что поддерживается как text/plain , но я собираюсь рассказать об этом, но в данный момент это не имеет значения.
В моем onActivityResult() я использовал то же самое, что и @Lukas Knuth , но не знаю, могу ли я с ним Copy этот File в другую часть из своей SDcard которую я ожидаю от его ответа.
EDIT с кодом, работающим благодаря @YS , @Lukas Knuth и @CommonsWare .
Это Intent когда я принимаю только файлы text/plain .
На моем onActivityResult() я создаю URI где я получаю данные Intent , я создаю File котором я сохраняю абсолютный путь, делающий content_describer.getPath(); , А затем я сохраняю имя пути, чтобы использовать его в TextView с content_describer.getLastPathSegment(); (Это было потрясающе @YS не знало об этой функции), и я создаю второй File который я назвал destination и я отправляю AbsolutePath для создания этого File .
Также я создал функцию, которую вы должны отправить source file и destination file который мы создали ранее, чтобы скопировать его в новую папку.
Также я создал функцию, которая говорит мне, если эта папка существует или нет (я должен отправить destination file , если он не существует, я создаю эту папку, и если это не так, я ничего не делаю.
Еще раз спасибо за вашу помощь, надеюсь, вам понравится этот код, сделанный со всеми вами, ребята 🙂
ШАГ 1 – Используйте неявное Intent :
Чтобы выбрать файл с устройства, вы должны использовать неявное Intent
ШАГ 2 – Получить абсолютный путь к файлу:
Чтобы получить путь к файлу из Uri , сначала попробуйте использовать
Где data – это Intent возвращаемое в onActivityResult() .
Если это не сработает, используйте следующий метод:
По крайней мере один из этих двух методов должен дать вам правильный полный путь.
ШАГ 3 – Скопируйте файл:
Я считаю, что вы хотите скопировать файл из одного места в другое.
Для этого абсолютно необходимо иметь абсолютный путь к файлу как источника, так и места назначения.
Во-первых, получите абсолютный путь к файлу, используя либо метод uri.getPath() либо uri.getPath() :
Затем создайте два объекта File следующим образом:
Где CustomFolder – это каталог на вашем внешнем диске, на котором вы хотите скопировать файл.
Затем используйте следующий метод для копирования файла из одного места в другое:
Попробуй это. Это должно сработать.
Примечание: ответ Vis-a-vis Lukas – то, что он сделал, – это использовать метод openInputStream() который возвращает содержимое Uri , независимо от того, представляет ли Uri файл или URL-адрес.
Другой перспективный подход – FileProvider :
Есть еще один способ, с помощью которого можно получить файл из другого приложения. Если приложение совместно использует свои файлы через FileProvider , тогда можно получить объект FileDescriptor который содержит определенную информацию об этом файле.
Для этого используйте следующий Intent :
И в вашем onActivityResult() :
Где mInputPFD – ParcelFileDescriptor .
Рекомендации:
1. Общие намерения – хранение файлов .
2. FileChannel .
3. FileProvider .
4. Запрос общего файла .
Я сделал то же самое, чтобы пользователь мог выбрать изображение из папки:
1) есть кнопка ОТКРЫТО:
2) открытая функция папки изображений:
3) результат активности, когда я получаю путь к файлу изображения и делаю все, что захочу, с помощью пути изображения:
4) и теперь САМАЯ ВАЖНАЯ ЧАСТЬ, класс W_ImgFilePathUtil, код не от меня, но он позволяет вам получить полный путь к любому выбранному файлу, будь то на SD-карте, диске Google …:
Открытый класс W_ImgFilePathUtil <
ЗАКЛЮЧЕНИЕ: код работает с контуром изображения, но обязательно работает с любым файлом.
Надеюсь, это поможет решить вашу проблему.
Uri не файл . Uri ближе к URL-адресу веб-сервера. Это непрозрачный адрес, который имеет смысл только для «сервера» (или в этом случае ContentProvider ).
Так же, как вы используете InputStream для чтения в байтах, представленных веб-URL, вы используете InputStream для чтения в байтах, представленных Uri . Вы получаете такой поток, вызывая openInputStream() на ContentResolver .
Как уже отмечалось в @CommonsWare , Android возвращает вам Uri , который является более абстрактным понятием, чем путь к файлу.
Он также может описывать простой путь к файлу, но он также может описывать ресурс, доступ к которому осуществляется через приложение (например, content://media/external/audio/media/710 ).
Если вы хотите, чтобы ваш пользователь выбрал любой файл с телефона, чтобы прочитать его из приложения, вы можете сделать это, запросив файл (как вы сделали правильно), а затем используйте ContentResolver чтобы получить InputStream для Uri который возвращается Сборщик.
Важно : некоторые поставщики (например, Dropbox) хранят / кэшируют свои данные во внешнем хранилище. Вам нужно будет указать android.permission.READ_EXTERNAL_STORAGE -передачу, объявленную в вашем манифесте, иначе вы получите FileNotFoundException , даже если файл есть.
Обновление : Да, вы можете скопировать файл, читая его из одного потока и записывая его в другой:
Удаление файла, вероятно, невозможно, так как файл не принадлежит вам, он принадлежит к приложению, которое поделилось им с вашим. Поэтому для удаления файла ответственное приложение отвечает за удаление.
Передайте URI, возвращенный в onActivityResult в этом методе
Источник