Android inputstream from uri

Получить FileInputStream из URI контента Android (или как искать по InputStream)

У меня есть приложение для видеоплеера, которое воспроизводит пользовательские транспортные потоки h264. Мне было поручено запустить наш плеер с помощью таких методов, как открытие пользователем «галереи», выбор «фильмов» и выбор фильма после выбора нашего приложения для запуска . все это работает отлично. Моя проблема в том, как выполнять поиск вперед и назад по InputStream с помощью ContentResolver.

Я также прочитал здесь много сообщений, например Android : Получение URI файла из URI контента?, а также тирады http://commonsware.com/blog/2013/08/07/for-android-apis-think-streams-not-files.html об использовании InputStream по сравнению с другими методами, но с большими видеофайлами пропуск и отметка / сброс не будут работать для поиска в нашем плеере, поэтому простой InputStream бесполезен . FileInputStream отлично работает, и в качестве взлома я использовал resolver.getInputStream в FileInputStream, и он играл в мяч, но это хак . итак . как мне получить объект File или FileInputStream из uri содержимого? или как я могу эффективно искать во входном потоке?

2 ответа

Таким образом, хотя возможно, что URI контента не поддерживается файлом, можно определить, является ли он . Вы можете использовать getStatSize из ParcelFileDescriptor, и он вернет значение, если резервный ресурс является файлом, и -1, если нет. Если это файл, то, очевидно, вы можете получить FileInputStream и соответствующий канал

Моя проблема в том, как выполнять поиск назад и вперед по InputStream с помощью ContentResolver

Это не всегда возможно. Это зависит от того, как ContentProvider поставляет содержимое InputStream . Если он использует ParcelFileDescriptor , поддерживаемый файлом, поток будет доступен для поиска. Если он использует ParcelFileDescriptor , поддерживаемый каналом, созданным createPipe() , поток не будет доступен для поиска. Я не тестировал некоторые из новых вариантов каналов на ParcelFileDescriptor , но я ожидал, что они также не будут доступны для поиска.

но с большими видеофайлами пропуск и отметка / сброс не будут работать для поиска в нашем плеере

Я ожидал, что этот метод будет работать для некоторых, но не для всех, значений content:// Uri . Если вы говорите, что вам нужно что-то другое, кроме skip() , mark() и reset() , то я не совсем понимаю, что вы имеете в виду.

FileInputStream отлично работает, и в качестве взлома я передал resolver.getInputStream в FileInputStream, и он играл в мяч

Это уж точно не будет надежно «играть в мяч». Более того, это может показаться бесполезным, поскольку я не вижу подходящих для вашего сценария методов на FileInputStream , которые не унаследованы от < >. Примечательно, что mark() , reset() и skip() находятся на InputStream .

как получить объект File или FileInputStream из uri содержимого?

Вы этого не сделаете. Например, видеофайл может находиться на съемном носителе, а на Android 4.4+ у вас нет прямого доступа к файлам на съемном носителе.

как я могу эффективно искать во входном потоке?

Если markSupported() возвращает истину, используйте mark() и reset() . Если нет, сообщите пользователю, что вы не можете воспроизвести этот поток, или отключите параметры, требующие поиска, или выполните собственное кэширование (например, для операций перемотки) данных, которые вы читаете из потока.

Источник

Читайте также:  Marshall наушники для андроид

Как использовать содержимое из 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 использовал реальное имя файла в качестве последнего сегмента пути.

Читайте также:  Java virtual machine для android

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 намного более гибкое и предлагает больше различных параметров безопасности.

Источник

Android inputstream from uri

FileInputStream is meant for reading streams of raw bytes such as image data. For reading streams of characters, consider using FileReader .

Constructor Summary

Constructors
Constructor and Description
FileInputStream (File file)

Method Summary

All Methods Instance Methods Concrete Methods
Modifier and Type Method and Description
int available ()

Methods inherited from class java.io.InputStream

Methods inherited from class java.lang.Object

Constructor Detail

FileInputStream

First, if there is a security manager, its checkRead method is called with the name argument as its argument.

If the named file does not exist, is a directory rather than a regular file, or for some other reason cannot be opened for reading then a FileNotFoundException is thrown.

FileInputStream

First, if there is a security manager, its checkRead method is called with the path represented by the file argument as its argument.

If the named file does not exist, is a directory rather than a regular file, or for some other reason cannot be opened for reading then a FileNotFoundException is thrown.

FileInputStream

If there is a security manager, its checkRead method is called with the file descriptor fdObj as its argument to see if it’s ok to read the file descriptor. If read access is denied to the file descriptor a SecurityException is thrown.

If fdObj is null then a NullPointerException is thrown.

This constructor does not throw an exception if fdObj is invalid . However, if the methods are invoked on the resulting stream to attempt I/O on the stream, an IOException is thrown.

Method Detail

The skip method may, for a variety of reasons, end up skipping over some smaller number of bytes, possibly 0 . If n is negative, the method will try to skip backwards. In case the backing file does not support backward skip at its current position, an IOException is thrown. The actual number of bytes skipped is returned. If it skips forwards, it returns a positive value. If it skips backwards, it returns a negative value.

This method may skip more bytes than what are remaining in the backing file. This produces no exception and the number of bytes skipped may include some number of bytes that were beyond the EOF of the backing file. Attempting to read from the stream after skipping past the end will result in -1 indicating the end of the file.

available

In some cases, a non-blocking read (or skip) may appear to be blocked when it is merely slow, for example when reading large files over slow networks.

close

If this stream has an associated channel then the channel is closed as well.

getFD

getChannel

The initial position of the returned channel will be equal to the number of bytes read from the file so far. Reading bytes from this stream will increment the channel’s position. Changing the channel’s position, either explicitly or by reading, will change this stream’s file position.

finalize

  • Summary:
  • Nested |
  • Field |
  • Constr |
  • Method
  • Detail:
  • Field |
  • Constr |
  • Method

Submit a bug or feature
For further API reference and developer documentation, see Java SE Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.
Copyright © 1993, 2021, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Also see the documentation redistribution policy.

Источник

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