W mojej aplikacji użytkownik wybiera plik audio, który aplikacja obsługuje. Problem polega na tym, że aby aplikacja robiła to, co chcę, aby robiła z plikami audio, potrzebuję, aby identyfikator URI był w formacie pliku. Kiedy używam natywnego odtwarzacza muzyki Androida do przeglądania pliku audio w aplikacji, URI to identyfikator URI treści, który wygląda następująco:
content://media/external/audio/media/710
Jednak korzystając z popularnej aplikacji do zarządzania plikami Astro, otrzymuję:
file:///sdcard/media/audio/ringtones/GetupGetOut.mp3
Ta ostatnia jest dla mnie znacznie bardziej dostępna do pracy, ale oczywiście chcę, aby aplikacja miała funkcjonalność z plikiem audio, który wybiera użytkownik, niezależnie od programu, którego używa do przeglądania swojej kolekcji. Więc moje pytanie brzmi: czy istnieje sposób na przekonwertowanie content://
stylu URI na file://
URI? W przeciwnym razie, co byś mi polecił, aby rozwiązać ten problem? Oto kod, który wywołuje selektor, w celach informacyjnych:
Intent ringIntent = new Intent();
ringIntent.setType("audio/mp3");
ringIntent.setAction(Intent.ACTION_GET_CONTENT);
ringIntent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(ringIntent, "Select Ringtone"), SELECT_RINGTONE);
Wykonuję następujące czynności z identyfikatorem URI treści:
m_ringerPath = m_ringtoneUri.getPath();
File file = new File(m_ringerPath);
Następnie zrób coś FileInputStream z tym plikiem.
Odpowiedzi:
Po prostu użyj,
getContentResolver().openInputStream(uri)
aby pobraćInputStream
z URI.http://developer.android.com/reference/android/content/ContentResolver.html#openInputStream(android.net.Uri)
źródło
To stara odpowiedź z przestarzałym i nieuczciwym sposobem na przezwyciężenie niektórych problemów z rozpoznawaniem treści. Weź to z ogromnymi ziarnami soli i użyj odpowiedniego interfejsu API openInputStream, jeśli to w ogóle możliwe.
Możesz użyć narzędzia Content Resolver, aby uzyskać
file://
ścieżkę zcontent://
identyfikatora URI:String filePath = null; Uri _uri = data.getData(); Log.d("","URI = "+ _uri); if (_uri != null && "content".equals(_uri.getScheme())) { Cursor cursor = this.getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null); cursor.moveToFirst(); filePath = cursor.getString(0); cursor.close(); } else { filePath = _uri.getPath(); } Log.d("","Chosen path = "+ filePath);
źródło
android.provider.MediaStore.Images.ImageColumns.DATA
) zawsze istnieje, jeśli schemat tak jestcontent://
?File
podczas próby ominięcia ContentResolver. Używaj metod ContentResolver do operowania nacontent://
URIS, jest to oficjalne podejście, do którego zachęcają inżynierowie Google.Jeśli masz z Uri treści
content://com.externalstorage...
, możesz użyć tej metody, aby uzyskać bezwzględną ścieżkę folderu lub pliku w systemie Android 19 lub nowszym .public static String getPath(final Context context, final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { System.out.println("getPath() uri: " + uri.toString()); System.out.println("getPath() uri authority: " + uri.getAuthority()); System.out.println("getPath() uri path: " + uri.getPath()); // ExternalStorageProvider if ("com.android.externalstorage.documents".equals(uri.getAuthority())) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; System.out.println("getPath() docId: " + docId + ", split: " + split.length + ", type: " + type); // This is for checking Main Memory if ("primary".equalsIgnoreCase(type)) { if (split.length > 1) { return Environment.getExternalStorageDirectory() + "/" + split[1] + "/"; } else { return Environment.getExternalStorageDirectory() + "/"; } // This is for checking SD Card } else { return "storage" + "/" + docId.replace(":", "/"); } } } return null; }
Możesz sprawdzić, czy każda część Uri używa println. Zwracane wartości dla mojej karty SD i pamięci głównej urządzenia są wymienione poniżej. Możesz uzyskać dostęp i usunąć plik, jeśli plik znajduje się w pamięci, ale nie byłem w stanie usunąć pliku z karty SD za pomocą tej metody, tylko odczytaj lub otwórz obraz, używając tej bezwzględnej ścieżki. Jeśli znajdziesz rozwiązanie do usunięcia za pomocą tej metody, udostępnij. KARTA SD
getPath() uri: content://com.android.externalstorage.documents/tree/612E-B7BF%3A/document/612E-B7BF%3A getPath() uri authority: com.android.externalstorage.documents getPath() uri path: /tree/612E-B7BF:/document/612E-B7BF: getPath() docId: 612E-B7BF:, split: 1, type: 612E-B7BF
PAMIĘĆ GŁÓWNA
getPath() uri: content://com.android.externalstorage.documents/tree/primary%3A/document/primary%3A getPath() uri authority: com.android.externalstorage.documents getPath() uri path: /tree/primary:/document/primary: getPath() docId: primary:, split: 1, type: primary
Jeśli chcesz uzyskać Uri
file:///
po uzyskaniu użycia ścieżkiDocumentFile documentFile = DocumentFile.fromFile(new File(path)); documentFile.getUri() // will return a Uri with file Uri
źródło
Próba obsłużenia identyfikatora URI ze schematem content: // przez wywołanie
ContentResolver.query()
nie jest dobrym rozwiązaniem. W HTC Desire z systemem 4.2.2 w wyniku zapytania można uzyskać NULL.Dlaczego zamiast tego nie użyć ContentResolver? https://stackoverflow.com/a/29141800/3205334
źródło
content://
identyfikator URI, odpowiadający plikowi w jej prywatnym katalogu wewnętrznym, nie będzie można używać tego URI zFile
interfejsami API w nowych wersjach Androida. ContentResolver został zaprojektowany, aby przezwyciężyć tego rodzaju ograniczenia bezpieczeństwa. Jeśli masz uri z ContentResolver, możesz oczekiwać, że po prostu zadziała.Inspirujące odpowiedzi to Jason LaBrun i Darth Raven . Próbowanie już odpowiedzi na pytania doprowadziło mnie do poniższego rozwiązania, które może głównie obejmować przypadki zerowe kursora i konwersję z content: // do file: //
Aby przekonwertować plik, przeczytaj i zapisz plik z uzyskanego URI
public static Uri getFilePathFromUri(Uri uri) throws IOException { String fileName = getFileName(uri); File file = new File(myContext.getExternalCacheDir(), fileName); file.createNewFile(); try (OutputStream outputStream = new FileOutputStream(file); InputStream inputStream = myContext.getContentResolver().openInputStream(uri)) { FileUtil.copyStream(inputStream, outputStream); //Simply reads input to output stream outputStream.flush(); } return Uri.fromFile(file); }
Aby uzyskać użycie nazwy pliku, zakryje ona wielkość liter kursora
public static String getFileName(Uri uri) { String fileName = getFileNameFromCursor(uri); if (fileName == null) { String fileExtension = getFileExtension(uri); fileName = "temp_file" + (fileExtension != null ? "." + fileExtension : ""); } else if (!fileName.contains(".")) { String fileExtension = getFileExtension(uri); fileName = fileName + "." + fileExtension; } return fileName; }
Istnieje dobra opcja konwersji z typu MIME na rozszerzenie pliku
public static String getFileExtension(Uri uri) { String fileType = myContext.getContentResolver().getType(uri); return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType); }
Kursor do uzyskania nazwy pliku
public static String getFileNameFromCursor(Uri uri) { Cursor fileCursor = myContext.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null); String fileName = null; if (fileCursor != null && fileCursor.moveToFirst()) { int cIndex = fileCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); if (cIndex != -1) { fileName = fileCursor.getString(cIndex); } } return fileName; }
źródło
Cóż, spóźniłem się na odpowiedź, ale mój kod jest testowany
sprawdź schemat z uri:
byte[] videoBytes; if (uri.getScheme().equals("content")){ InputStream iStream = context.getContentResolver().openInputStream(uri); videoBytes = getBytes(iStream); }else{ File file = new File(uri.getPath()); FileInputStream fileInputStream = new FileInputStream(file); videoBytes = getBytes(fileInputStream); }
W powyższej odpowiedzi przekonwertowałem wideo uri na tablicę bajtów, ale to nie jest związane z pytaniem, po prostu skopiowałem mój pełny kod, aby pokazać użycie
FileInputStream
iInputStream
ponieważ oba działają tak samo w moim kodzie.Użyłem kontekstu zmiennej, którym jest getActivity () w moim fragmencie, aw działaniu jest to po prostu nazwa działania. To
context=getActivity();
// we fragmenciecontext=ActivityName.this;
// w działaniuźródło
byte[] videoBytes;
? Większość odpowiedzi pokazuje tylko, jak używaćInputStream
z obrazem.Spróbuj tego....
pobierz plik z uri zawartości
fun fileFromContentUri(context: Context, contentUri: Uri): File { // Preparing Temp file name val fileExtension = getFileExtension(context, contentUri) val fileName = "temp_file" + if (fileExtension != null) ".$fileExtension" else "" // Creating Temp file val tempFile = File(context.cacheDir, fileName) tempFile.createNewFile() try { val oStream = FileOutputStream(tempFile) val inputStream = context.contentResolver.openInputStream(contentUri) inputStream?.let { copy(inputStream, oStream) } oStream.flush() } catch (e: Exception) { e.printStackTrace() } return tempFile } private fun getFileExtension(context: Context, uri: Uri): String? { val fileType: String? = context.contentResolver.getType(uri) return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType) } @Throws(IOException::class) private fun copy(source: InputStream, target: OutputStream) { val buf = ByteArray(8192) var length: Int while (source.read(buf).also { length = it } > 0) { target.write(buf, 0, length) } }
źródło