Android: Einen Datei-URI von einem Inhalts-URI erhalten?

Lesezeit: 9 Minuten

Android Einen Datei URI von einem Inhalts URI erhalten
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:

file:///sdcard/media/audio/ringtones/GetupGetOut.mp3

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:

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);

Ich mache folgendes mit dem Inhalts-URI:

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

1645911189 950 Android Einen Datei URI von einem Inhalts URI erhalten
Jason LeBrun

Benutz einfach getContentResolver().openInputStream(uri) ein zu bekommen InputStream von einem URI.

http://developer.android.com/reference/android/content/ContentResolver.html#openInputStream(android.net.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

Android Einen Datei URI von einem Inhalts URI erhalten
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:

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);

  • 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


Android Einen Datei URI von einem Inhalts URI erhalten
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 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;
}

Es gibt eine gute Option zum Konvertieren vom MIME-Typ in die Dateierweiterung

 public static String getFileExtension(Uri uri) {
    String fileType = myContext.getContentResolver().getType(uri);
    return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType);
}

Cursor zum Abrufen des Dateinamens

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

1645911191 159 Android Einen Datei URI von einem Inhalts URI erhalten
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

1645911191 944 Android Einen Datei URI von einem Inhalts URI erhalten
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

868440cookie-checkAndroid: Einen Datei-URI von einem Inhalts-URI erhalten?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy