Android: Einen Datei-URI von einem Inhalts-URI erhalten?
Lesezeit: 9 Minuten
JMRboosties
In meiner App soll der Benutzer eine Audiodatei auswählen, die die App dann verarbeitet. Das Problem ist, dass die URI im Dateiformat vorliegen muss, damit die App mit den Audiodateien das tun kann, was ich möchte. Wenn ich den nativen Musikplayer von Android verwende, um in der App nach der Audiodatei zu suchen, ist der URI ein Inhalts-URI, der so aussieht:
content://media/external/audio/media/710
Wenn ich jedoch die beliebte Dateimanager-Anwendung Astro verwende, erhalte ich Folgendes:
Letzteres ist für mich viel zugänglicher, aber natürlich möchte ich, dass die App mit der Audiodatei funktioniert, die der Benutzer auswählt, unabhängig davon, welches Programm er zum Durchsuchen seiner Sammlung verwendet. Daher meine Frage, gibt es eine Möglichkeit, das umzuwandeln content:// Stil-URI in a file:// URI? Was würden Sie mir sonst empfehlen, um dieses Problem zu lösen? Hier ist der Code, der die Auswahl aufruft, als Referenz:
m_ringerPath = m_ringtoneUri.getPath();
File file = new File(m_ringerPath);
Machen Sie dann etwas FileInputStream-Zeug mit dieser Datei.
Welche Aufrufe verwenden Sie, die keine Inhalts-URIs mögen?
– Phil Lello
14. April 2011 um 1:04 Uhr
Es gibt viele Inhalts-URIs, bei denen Sie den Dateipfad nicht erhalten können, da nicht alle Inhalts-URIS verfügen über Dateipfade. Verwenden Sie keine Dateipfade.
– Muhende Ente
13. April 2016 um 0:57 Uhr
Jason LeBrun
Benutz einfach getContentResolver().openInputStream(uri) ein zu bekommen InputStream von einem URI.
Überprüfen Sie das Schema des URI, der Ihnen von der Auswahlaktivität zurückgegeben wurde. Wenn uri.getScheme.equals(“content”), öffnen Sie es mit einem Content-Resolver. Wenn die uri.Scheme.equals(“Datei”), öffnen Sie sie mit normalen Dateimethoden. So oder so erhalten Sie am Ende einen InputStream, den Sie mit allgemeinem Code verarbeiten können.
– Jason LeBrun
14. April 2011 um 1:37 Uhr
Eigentlich habe ich gerade die Dokumentation für getContentResolver().openInputStream() erneut gelesen, und es funktioniert automatisch für Schemata von “Inhalt” oder “Datei”, also Sie nicht müssen Sie das Schema überprüfen … wenn Sie sicher davon ausgehen können, dass es immer content:// oder file:// sein wird, dann wird openInputStream() immer funktionieren.
– Jason LeBrun
14. April 2011 um 1:50 Uhr
Gibt es eine Möglichkeit, die Datei anstelle des InputStream (aus Inhalt: …) zu erhalten?
– AlikElzin-kilaka
15. März 2012 um 11:47 Uhr
@kilaka Sie können den Dateipfad abrufen, aber es ist schmerzhaft. Siehe stackoverflow.com/a/20559418/294855
– Danyal Aytekin
22. Mai 2014 um 11:21 Uhr
Diese Antwort ist unzureichend für jemanden, der eine Closed-Source-API verwendet, die eher auf Dateien als auf FileStreams angewiesen ist, aber dennoch das Betriebssystem verwenden möchte, um dem Benutzer die Auswahl der Datei zu ermöglichen. Die Antwort, auf die @DanyalAytekin verwies, war genau das, was ich brauchte (und tatsächlich konnte ich viel Fett kürzen, weil ich genau weiß, mit welchen Arten von Dateien ich arbeite).
– Affe0506
20. November 2015 um 12:45 Uhr
Raffael Nobre
Dies ist eine alte Antwort mit veralteter und hackiger Methode zur Überwindung einiger spezifischer Schmerzpunkte des Content-Resolvers. Nehmen Sie es mit einigen großen Salzkörnern und verwenden Sie nach Möglichkeit die richtige openInputStream-API.
Sie können den Content Resolver verwenden, um eine zu erhalten file:// Weg von der content:// URI:
Danke, das hat perfekt funktioniert. Ich konnte keinen InputStream verwenden, wie die akzeptierte Antwort vorschlägt.
– ldam
8. Mai 2013 um 20:07 Uhr
Dies funktioniert nur für lokale Dateien, zB nicht für Google Drive
– Paulgawrikow
29. Juli 2015 um 11:51 Uhr
Funktioniert manchmal, gibt manchmal file:///storage/emulated/0/… zurück, was nicht existiert.
– Reza Mohammadi
31. Januar 2016 um 20:58 Uhr
Ist die Spalte “_data” (android.provider.MediaStore.Images.ImageColumns.DATA) immer garantiert, wenn die Regelung vorhanden ist content://?
– Eduard Falk
31. März 2016 um 1:14 Uhr
Dies ist ein wichtiges Anti-Pattern. Einige ContentProvider stellen diese Spalte bereit, aber es ist nicht garantiert, dass Sie darauf Lese-/Schreibzugriff haben File wenn Sie versuchen, ContentResolver zu umgehen. Verwenden Sie ContentResolver-Methoden, um damit zu arbeiten content:// uris, das ist der offizielle Ansatz, der von Google-Ingenieuren gefördert wird.
– Benutzer1643723
10. Januar 2017 um 11:38 Uhr
Thrakisch
Wenn Sie einen Inhalt mit Uri haben content://com.externalstorage... Sie können diese Methode verwenden, um den absoluten Pfad eines Ordners oder einer Datei zu erhalten auf Android 19 oder höher.
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;
}
Sie können jeden Teil von Uri mit überprüfen println. Zurückgegebene Werte für meine SD-Karte und den Hauptspeicher des Geräts sind unten aufgeführt. Sie können darauf zugreifen und löschen, wenn sich die Datei im Speicher befindet, aber ich konnte dies nicht Datei von der SD-Karte löschen Verwenden Sie diese Methode, um nur Bilder mit diesem absoluten Pfad zu lesen oder zu öffnen. Wenn Sie eine Lösung zum Löschen mit dieser Methode finden, teilen Sie sie bitte mit.
SD-KARTE
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
HAUPTERINNERUNG
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
Wenn Sie möchten, dass Uri mitkommt file:/// nach Erhalt der Pfadnutzung
DocumentFile documentFile = DocumentFile.fromFile(new File(path));
documentFile.getUri() // will return a Uri with file Uri
Ich denke nicht, dass dies der richtige Weg ist, dies in einer Anwendung zu tun. leider verwende ich es in einem Quicky-Projekt
– Bondax
22. Juni 2018 um 21:45 Uhr
@Bondax Ja, Sie sollten mit Content Uris statt Dateipfaden oder File Uris arbeiten. Auf diese Weise wird das Framework für den Speicherzugriff eingeführt. Wenn Sie jedoch Datei-URI erhalten möchten, ist dies der korrekteste Weg für andere Antworten, da Sie die DocumentsContract-Klasse verwenden. Wenn Sie sich Google-Beispiele in Github ansehen, werden Sie feststellen, dass sie diese Klasse auch verwenden, um Unterordner eines Ordners abzurufen.
– Thrakisch
23. Juni 2018 um 5:32 Uhr
Und die DocumentFile-Klasse ist auch neu in API 19 und wie Sie URIS von SAF verwenden. Der richtige Weg besteht darin, einen Standardpfad für Ihre App zu verwenden und den Benutzer zu bitten, die Berechtigung für einen Ordner über die SAF-Benutzeroberfläche zu erteilen, die Uri-Zeichenfolge in den freigegebenen Einstellungen zu speichern und bei Bedarf auf den Ordner mit DocumentFile-Objekten zuzugreifen
– Thrakisch
23. Juni 2018 um 5:36 Uhr
Versuche dies….
Holen Sie sich eine Datei aus einem Inhalts-URI
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)
}
}
Inspirierte Antworten sind Jason LaBrun & Darth Raven. Das Ausprobieren bereits beantworteter Ansätze führte mich zu der folgenden Lösung, die hauptsächlich Cursor-Nullfälle und -Konvertierungen abdecken kann Inhalt:// zu Datei://
Um die Datei zu konvertieren, lesen und schreiben Sie die Datei aus dem gewonnenen 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);
}
Um den Dateinamen zu verwenden, wird der Nullfall des Cursors behandelt
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;
}
Danke, schaue mir das seit einer Woche an. Ich mag es nicht, dafür eine Datei zu kopieren, aber es funktioniert.
– justdan0227
26. Mai 2020 um 19:00 Uhr
Gemeinschaft
Versuch, den URI mit dem Schema content:// durch Aufrufen zu verarbeiten ContentResolver.query()ist keine gute Lösung. Auf HTC Desire mit 4.2.2 könnten Sie NULL als Abfrageergebnis erhalten.
Warum nicht stattdessen ContentResolver verwenden? https://stackoverflow.com/a/29141800/3205334
Danke, schaue mir das seit einer Woche an. Ich mag es nicht, dafür eine Datei zu kopieren, aber es funktioniert.
– justdan0227
26. Mai 2020 um 19:00 Uhr
Umar Ata
Nun, ich bin etwas spät zu antworten, aber mein Code ist getestet
Prüfschema aus 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);
}
In der obigen Antwort habe ich den Video-URI in bytes array konvertiert, aber das hat nichts mit der Frage zu tun, ich habe nur meinen vollständigen Code kopiert, um die Verwendung von zu zeigen FileInputStream und InputStream da beide in meinem Code gleich funktionieren.
Ich habe den Variablenkontext getActivity() in meinem Fragment verwendet und in Activity ist es einfach ActivityName.this
context=getActivity(); // im Fragment
context=ActivityName.this;// aktiv
Ich weiß, es hängt nicht mit der Frage zusammen, aber wie würdest du das dann verwenden byte[] videoBytes;? Die meisten Antworten zeigen nur die Verwendung InputStream mit einem Bild.
– KRK
1. Oktober 2019 um 4:44 Uhr
8684400cookie-checkAndroid: Einen Datei-URI von einem Inhalts-URI erhalten?yes
Welche Aufrufe verwenden Sie, die keine Inhalts-URIs mögen?
– Phil Lello
14. April 2011 um 1:04 Uhr
Es gibt viele Inhalts-URIs, bei denen Sie den Dateipfad nicht erhalten können, da nicht alle Inhalts-URIS verfügen über Dateipfade. Verwenden Sie keine Dateipfade.
– Muhende Ente
13. April 2016 um 0:57 Uhr