Holen Sie sich Content Uri aus dem Dateipfad in Android

271

Ich kenne den absoluten Pfad eines Bildes (z. B. /sdcard/cats.jpg). Gibt es eine Möglichkeit, den Inhalt uri für diese Datei zu erhalten?

Tatsächlich lade ich in meinem Code ein Bild herunter und speichere es an einem bestimmten Ort. Um das Bild in einer ImageView-Instanz festzulegen, öffne ich derzeit die Datei über den Pfad, erhalte die Bytes, erstelle eine Bitmap und setze dann die Bitmap in der ImageView-Instanz. Dies ist ein sehr langsamer Prozess. Wenn ich stattdessen den Inhalt uri erhalten könnte, könnte ich die Methode sehr einfach verwenden imageView.setImageUri(uri)

pankajagarwal
quelle
23
Uri uri = Uri.parse ("file: ///sdcard/img.png");
Anand Tiwari
13
+1 zum Kommentar, nur Uri.parse ("file: //" + filePath) sollte den Trick machen
Deutscher Latorre
Uri.Parse wird abgeschrieben und "hinzugefügt"
Pollaris
@pollaris Uri.parse wurde in API 1 hinzugefügt und ist nicht als veraltet markiert.
JP de la Torre
Uri.parse ("etwas"); arbeitet nicht an mir, ich kann den Grund nicht finden warum ...
Bay

Antworten:

480

Versuche es mit:

ImageView.setImageURI(Uri.fromFile(new File("/sdcard/cats.jpg")));

Oder mit:

ImageView.setImageURI(Uri.parse(new File("/sdcard/cats.jpg").toString()));
Francesco Laurita
quelle
3
Vielen Dank! Die zweite Methode funktioniert gut auf 1.6, 2.1 und 2.2, aber die erste nur auf 2.2
Mischkin
28
Keine dieser Methoden löst einen Dateipfad zu einem Inhalts-URI auf. Ich verstehe, dass es das unmittelbare Problem gelöst hat.
Jeffrey Blattman
38
Nicht fest codieren "/ sdcard /"; Verwenden Sie stattdessen Environment.getExternalStorageDirectory (). getPath ()
ekatz
8
Dies ist, was beide oben genannten Lösungen zurückgeben: 1. Datei: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 Aber was ich gesucht habe denn ist etwas anderes. Ich brauche den Inhalt: // URI formatieren. Die Antwort von Jinal scheint perfekt zu funktionieren
Ajith Memana
5
Hey Uri.fromFilewird nicht auf Android 26+ funktionieren, sollten Sie
Dateianbieter
85

AKTUALISIEREN

Hier wird davon ausgegangen, dass Ihre Medien (Image / Video) bereits zum Content Media Provider hinzugefügt wurden. Wenn nicht, können Sie die Inhalts-URL nicht genau so erhalten, wie Sie es möchten. Stattdessen wird es Datei Uri geben.

Ich hatte dieselbe Frage für meine Datei-Explorer-Aktivität. Sie sollten wissen, dass die Datei contenturi for file nur Mediastore-Daten wie Bild, Audio und Video unterstützt. Ich gebe Ihnen den Code, um Bildinhalt uri von der Auswahl eines Bildes von der SD-Karte zu erhalten. Probieren Sie diesen Code aus, vielleicht funktioniert er für Sie ...

public static Uri getImageContentUri(Context context, File imageFile) {
  String filePath = imageFile.getAbsolutePath();
  Cursor cursor = context.getContentResolver().query(
      MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
      new String[] { MediaStore.Images.Media._ID },
      MediaStore.Images.Media.DATA + "=? ",
      new String[] { filePath }, null);
  if (cursor != null && cursor.moveToFirst()) {
    int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
    cursor.close();
    return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + id);
  } else {
    if (imageFile.exists()) {
      ContentValues values = new ContentValues();
      values.put(MediaStore.Images.Media.DATA, filePath);
      return context.getContentResolver().insert(
          MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    } else {
      return null;
    }
  }
}
Jinal Jogiyani
quelle
Ich suchte nach einer Methode, um den Inhalt zu finden: // URI meiner aufgezeichneten Videodatei, und der obige Code scheint unter Nexus 4 (Android 4.3) perfekt zu funktionieren. Es wäre schön, wenn Sie bitte den Code erklären können.
Ajith Memana
Ich habe versucht, den Content Uri für eine Datei mit dem absoluten Pfad "/ sdcard / Image Depo / picture.png" abzurufen. Es hat nicht funktioniert, also habe ich den Codepfad debuggt und festgestellt, dass der Cursor leer ist. Wenn der Eintrag zu ContentProvider hinzugefügt wird, gibt er null als Content Uri an. Bitte helfen Sie.
Sri Krishna
1
Ich habe den Dateipfad - file: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4, erhalte aber null, wenn ich versuche, contentUri abzurufen. Ich habe auch versucht Wechsel MediaStore.Images.Mediazu MediaStore.Video.Media, aber noch kein Glück.
Narendra Singh
1
Dies funktioniert nicht auf Android Pie API 28. Cursor gibt null zurück
Ibrahim Gharyali
1
Können Sie diese Methode für Android 10 aktualisieren, da auf die Spalte DATA in Android 10 nicht zugegriffen werden kann?
Khushbu Shah
16

// Dieser Code funktioniert für Bilder unter 2.2, nicht sicher, ob andere Medientypen vorhanden sind

   //Your file path - Example here is "/sdcard/cats.jpg"
   final String filePathThis = imagePaths.get(position).toString();

   MediaScannerConnectionClient mediaScannerClient = new
   MediaScannerConnectionClient() {
    private MediaScannerConnection msc = null;
    {
        msc = new MediaScannerConnection(getApplicationContext(), this);
        msc.connect();
    }

    public void onMediaScannerConnected(){
        msc.scanFile(filePathThis, null);
    }


    public void onScanCompleted(String path, Uri uri) {
        //This is where you get your content uri
            Log.d(TAG, uri.toString());
        msc.disconnect();
    }
   };
AndroidDebaser
quelle
1
Großartig, hat mir beim Teilen auf Google+ geholfen, da diese App einen Medienstream mit einem Uri-Inhalt erfordert - der absolute Pfad funktioniert nicht.
Ridcully
1
Ausgezeichnet! Ich kann bestätigen, dass dies auch mit Audiomedientypen funktioniert.
Matt M
16

Die akzeptierte Lösung ist wahrscheinlich die beste Wahl für Ihre Zwecke, aber um die Frage in der Betreffzeile tatsächlich zu beantworten:

In meiner App muss ich den Pfad von URIs und den URI von Pfaden abrufen. Das Vorherige:

/**
 * Gets the corresponding path to a file from the given content:// URI
 * @param selectedVideoUri The content:// URI to find the file path from
 * @param contentResolver The content resolver to use to perform the query.
 * @return the file path as a string
 */
private String getFilePathFromContentUri(Uri selectedVideoUri,
        ContentResolver contentResolver) {
    String filePath;
    String[] filePathColumn = {MediaColumns.DATA};

    Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}

Letzteres (was ich für Videos mache, aber auch für Audio oder Dateien oder andere Arten von gespeicherten Inhalten verwendet werden kann, indem MediaStore.Audio (usw.) für MediaStore.Video ersetzt wird):

/**
 * Gets the MediaStore video ID of a given file on external storage
 * @param filePath The path (on external storage) of the file to resolve the ID of
 * @param contentResolver The content resolver to use to perform the query.
 * @return the video ID as a long
 */
private long getVideoIdFromFilePath(String filePath,
        ContentResolver contentResolver) {


    long videoId;
    Log.d(TAG,"Loading file " + filePath);

            // This returns us content://media/external/videos/media (or something like that)
            // I pass in "external" because that's the MediaStore's name for the external
            // storage on my device (the other possibility is "internal")
    Uri videosUri = MediaStore.Video.Media.getContentUri("external");

    Log.d(TAG,"videosUri = " + videosUri.toString());

    String[] projection = {MediaStore.Video.VideoColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(projection[0]);
    videoId = cursor.getLong(columnIndex);

    Log.d(TAG,"Video ID is " + videoId);
    cursor.close();
    return videoId;
}

Grundsätzlich wird in der DATASpalte MediaStore(oder in dem von Ihnen abgefragten Unterabschnitt) der Dateipfad gespeichert, sodass Sie diese Informationen zum Nachschlagen verwenden.

Jon O.
quelle
Nicht immer der Fall, es werden zwei halbgarantierte Spalten zurückgegeben, und das heißt, OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEwenn die sendende App sogar den "Regeln" folgt. Ich habe festgestellt, dass einige wichtige Apps nur diese beiden Felder zurückgeben und nicht immer das _dataFeld. Wenn Sie nicht über das Datenfeld verfügen, das normalerweise einen direkten Pfad zum Inhalt enthält, müssen Sie zuerst den Inhalt lesen und in eine Datei oder in den Speicher schreiben, und dann haben Sie Ihren eigenen Pfad.
Pierre
7

Sie können diese beiden Möglichkeiten je nach Verwendung verwenden

Uri uri = Uri.parse("String file location");

oder

Uri uri = Uri.fromFile(new File("string file location"));

Ich habe beide Wege ausprobiert und beide funktionieren.

Abhishek Meharia
quelle
5

Die einfachste und robusteste Methode zum Erstellen von Content Uri content://aus einer Datei ist die Verwendung von FileProvider . Von FileProvider bereitgestelltes Uri kann auch verwendet werden, um Uri zum Teilen von Dateien mit anderen Apps bereitzustellen. Um File Uri von einem absoluten Pfad von zu erhalten File, können Sie DocumentFile.fromFile (neue Datei (Pfad, Name)) verwenden, die in Api 22 hinzugefügt wird und für die folgenden Versionen null zurückgibt.

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
Thraker
quelle
2

Abrufen der Datei-ID ohne Schreiben von Code, nur mit den CLI-Befehlen der ADB-Shell:

adb shell content query --uri "content://media/external/video/media" | grep FILE_NAME | grep -Eo " _id=([0-9]+)," | grep -Eo "[0-9]+"
BogdanBiv
quelle
Google "adb erhält einen echten Pfad von Content Uri" und diese Frage ist die Top 1, wobei der Inhalt Ihrer 0-Stimmen-Antwort in der Zusammenfassung der Suchergebnisse enthalten ist. Lassen Sie mich also der Erste sein, der abstimmt. Danke, Bro!
Wochenende
Das ist cool. Aber es scheint, Sie werden: bekommen Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, es sei denn, Sie sind verwurzelt.
not2qubit
Also braucht dies Root-Zugriff des Telefons?
Samintha Kaveesh
1

Verwenden Sie besser eine Validierung, um Versionen vor Android N zu unterstützen. Beispiel:

  if (Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N) {
     imageUri = Uri.parse(filepath);
  } else{
     imageUri = Uri.fromFile(new File(filepath));
  }

  if (Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N) {
     ImageView.setImageURI(Uri.parse(new File("/sdcard/cats.jpg").toString()));         
  } else{
     ImageView.setImageURI(Uri.fromFile(new File("/sdcard/cats.jpg")));
  }

https://es.stackoverflow.com/questions/71443/reporte-crash-android-os-fileuriexposedexception-en-android-n

Jorgesys
quelle
0

Sie können versuchen, unten Code-Snippet

    public Uri getUri(ContentResolver cr, String path){
    Uri mediaUri = MediaStore.Files.getContentUri(VOLUME_NAME);
    Cursor ca = cr.query(mediaUri, new String[] { MediaStore.MediaColumns._ID }, MediaStore.MediaColumns.DATA + "=?", new String[] {path}, null);
    if (ca != null && ca.moveToFirst()) {
        int id = ca.getInt(ca.getColumnIndex(MediaStore.MediaColumns._ID));
        ca.close();
        return  MediaStore.Files.getContentUri(VOLUME_NAME,id);
    }
    if(ca != null) {
        ca.close();
    }
    return null;
}
caopeng
quelle
1
Was ist VOLUME_NAME?
Evgenii Vorobei
Es ist "extern" oder "intern"
Caopeng