Android dosya yolundan içerik uri alın


271

Bir görüntünün mutlak yolunu biliyorum (örneğin, /sdcard/cats.jpg için). Bu dosya için uri içeriğini almanın herhangi bir yolu var mı?

Aslında kodumda bir resim indirip belirli bir yere kaydediyorum. Görüntüyü bir ImageView örneğinde ayarlamak için, şu anda dosyayı yolu kullanarak açıyorum, baytları alıyorum ve bir bitmap oluşturduktan sonra ImageView örneğinde bitmap'i ayarlıyorum. Bu çok yavaş bir işlemdir, bunun yerine uri içeriğini alabilirsem yöntemi kolayca kullanabilirim imageView.setImageUri(uri)


23
Uri uri = Uri.parse ("dosya: ///sdcard/img.png");
Anand Tiwari

13
Yoruma +1, sadece Uri.parse ("file: //" + filePath) hile yapmalı
Alman Latorre

Uri.Parse amortismana tabi tutuldu ve "eklenecek"
pollaris

@pollaris Uri.parse API 1'e eklendi ve kullanımdan kaldırılma için işaretlenmedi.
JP de la Torre

Uri.parse ( "bir şey"); bana çalışmıyor, nedenini bulamıyorum ...
Bay

Yanıtlar:


480

Şunu deneyin:

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

Veya:

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

3
Teşekkürler! İkinci yöntem 1.6, 2.1 ve 2.2'de iyi çalışıyor, ancak birincisi sadece 2.2'de çalışıyor
mishkin

28
bu yöntemlerin hiçbiri içerik URI'sı için bir dosya yolunu çözmez. Anında sorunu çözdüğünü anlıyorum.
Jeffrey Blattman

38
"/ Sdcard /" sabit kodunu kullanmayın; bunun yerine Environment.getExternalStorageDirectory (). getPath () kullanın
ekatz

8
Yukarıdaki çözümlerin her ikisi de şunu döndürür: 1. file: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 Ama neyi arıyordum çünkü farklı bir şeydir. İçeriğe ihtiyacım var: // format URI. Jinal'in cevabı mükemmel çalışıyor gibi görünüyor
Ajith Memana

5
hey Uri.fromFileandroid
26+

85

GÜNCELLEME

Burada medyanızın (Resim / Video) içerik medya sağlayıcısına zaten eklendiği varsayılmaktadır. Değilse, içerik URL'sini tam olarak ne istediğinizi alamazsınız. Bunun yerine Uri dosyası olacaktır.

Dosya gezgini etkinliği için de aynı sorum vardı. Dosya içeriğinin yalnızca resim, ses ve video gibi medya mağazası verilerini desteklediğini bilmelisiniz. Ben sdcard bir görüntü seçerek görüntü içeriği uri almak için kod veriyorum. Bu kodu deneyin, belki sizin için çalışacaktır ...

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

İçeriği bulmak için bir yöntem arıyordum: // Kaydedilmiş video dosyamın // URI'si ve yukarıdaki kod Nexus 4'te (Android 4.3) mükemmel çalışıyor gibi görünüyor. Kodu açıklayabilirseniz iyi olur.
Ajith Memana

Ben Mutlak yolu "/ sdcard / Image Depo / picture.png" olan bir dosya için içerik Uri almak için denedim. Bu işe yaramadı, bu yüzden kod yolunda hata ayıkladı ve İmleç boş olduğunu ve giriş ContentProvider eklenirken, İçerik Uri olarak null vererek bulundu. Lütfen yardım et.
Sri Krishna

1
Dosya yolum var - dosya: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4, ancak contentUri almaya çalıştığımda null alıyorum. Ayrıca değişen çalıştı MediaStore.Images.Mediaiçin MediaStore.Video.Mediahala şans ama.
Narendra Singh

1
Bu android Pie api 28 üzerinde çalışmıyor. İmleç null döndürür
İbrahim Gharyali

1
Android 10 için DATA sütununa erişilemediğinden bu yöntemi Android 10 için güncelleyebilir misiniz?
Khushbu Shah

16

// Bu kod 2.2'deki görüntüler için çalışır, başka ortam türlerinden emin değilim

   //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();
    }
   };

1
harika, Google + 'da paylaşımda bana yardımcı oldu, çünkü uygulama Uri içerikli bir medya akışı gerektiriyor - mutlak yol çalışmıyor.
12'de Ridcully

1
Mükemmel! Bunun Ses ortamı türleriyle de çalıştığını onaylayabilirim.
Matt M

16

Kabul edilen çözüm muhtemelen amaçlarınız için en iyi seçenektir, ancak konuyu konu satırında gerçekten cevaplamak için:

Uygulamamda, URI'lerden yolu almam ve URI'yi yollardan almam gerekiyor. Eski:

/**
 * 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;
}

İkincisi (videolar için yaptığım, ancak MediaStore.Video yerine MediaStore.Audio (vb) değiştirerek Ses veya Dosyalar veya diğer depolanan içerik türleri için de kullanılabilir):

/**
 * 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;
}

Temel olarak, (veya sorguladığınız alt bölümün) DATAsütunu MediaStoredosya yolunu depolar, böylece aramak için bu bilgileri kullanırsınız.


Her zaman böyle değil, iade edilen iki yarı garantili sütun vardır ve bu, OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEgönderen uygulamanın "kuralları" bile izlemesi durumundadır. Bazı büyük uygulamaların her zaman bu _dataalanı değil, yalnızca bu iki alanı döndürdüğünü gördüm . Normalde içeriğe doğrudan bir yol içeren veri alanına sahip değilseniz, önce içeriği okumalı ve bir dosyaya veya belleğe yazmalısınız, sonra kendi yolunuz var.
Pierre

7

Kullanıma bağlı olarak bu iki yolu kullanabilirsiniz

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

veya

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

Her iki yolu da denedim ve her ikisi de.


5

content://Bir Dosyadan İçerik Uri'si oluşturmanın en kolay ve sağlam yolu FileProvider kullanmaktır . FileProvider tarafından sağlanan Uri, diğer uygulamalarla da dosya paylaşmak için Uri sağlamak için de kullanılabilir. Dosya Uri'sini mutlak bir yoldan Fileelde etmek için DocumentFile.fromFile (yeni Dosya (yol, ad)) kullanabilirsiniz, Api 22'ye eklenir ve aşağıdaki sürümler için null değerini döndürür.

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


2

Sadece adb shell CLI komutlarıyla herhangi bir kod yazmadan Dosya Kimliğini elde etme:

adb shell content query --uri "content://media/external/video/media" | grep FILE_NAME | grep -Eo " _id=([0-9]+)," | grep -Eo "[0-9]+"

Google "adb, içerik uri'den gerçek bir yol al" dır ve bu soru ilk 1'dir ve 0 oylama yanıtlayıcınızın içeriği arama sonucu özetindedir. Öyleyse ilk oy veren olmama izin verin. Teşekkürler kardeşim!
Hafta Sonu

Bu havalı. Ama görünüşe göre alacaksın: Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLYeğer kök salmazsan.
not2qubit

yani bu telefonun root erişimi gerektiriyor mu?
Samintha Kaveesh

1

Android N öncesi sürümleri desteklemek için bir doğrulama kullanmak daha iyidir, örnek:

  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


0

Kod snippet'inin altında deneyebilirsiniz

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

1
VOLUME_NAME nedir?
Evgenii Vorobei

"Dış" veya "iç" olduğunu
caopeng
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.