รับ uri เนื้อหาจากเส้นทางของไฟล์ใน Android


271

ฉันรู้เส้นทางที่แน่นอนของรูปภาพ (เช่น for /sdcard/cats.jpg) มีวิธีการรับเนื้อหา uri สำหรับไฟล์นี้หรือไม่?

ที่จริงแล้วในรหัสของฉันฉันดาวน์โหลดภาพและบันทึกไว้ในสถานที่เฉพาะ ในการตั้งค่ารูปภาพในอินสแตนซ์ ImageView ปัจจุบันฉันเปิดไฟล์โดยใช้พา ธ รับไบต์และสร้างบิตแมปจากนั้นตั้งค่าบิตแมปในอินสแตนซ์ ImageView นี่เป็นกระบวนการที่ช้ามาก แต่ถ้าฉันสามารถรับเนื้อหา uri ได้ฉันก็สามารถใช้วิธีนี้ได้ง่ายมาก imageView.setImageUri(uri)


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

13
+1 กับความคิดเห็นเพียง Uri.parse ("file: //" + filePath) ควรทำเคล็ดลับ
German Latorre

Uri.Parse ถูกคิดค่าเสื่อมราคาและ "ต้องถูกเพิ่ม"
Pollaris

@pollaris Uri.parse ถูกเพิ่มใน API 1 และไม่มีการทำเครื่องหมายสำหรับการคัดค้าน
JP de la Torre

Uri.parse ( "อะไรบางอย่าง"); ไม่ทำงานกับฉันฉันไม่สามารถหาสาเหตุที่ ...
อ่าว

คำตอบ:


480

ลองด้วย:

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

หรือด้วย:

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

3
ขอบคุณ! วิธีที่สองทำงานได้ดีบน 1.6, 2.1 และ 2.2 แต่วิธีแรกใช้ได้เฉพาะวันที่ 2.2
mishkin

28
วิธีการเหล่านั้นไม่สามารถแก้ไขพา ธ ไฟล์ไปยัง URI เนื้อหา ฉันเข้าใจว่ามันแก้ปัญหาเฉพาะหน้าได้
Jeffrey Blattman

38
อย่าฮาร์ดโค้ด "/ sdcard /"; ใช้ Environment.getExternalStorageDirectory (). getPath () แทน
ekatz

8
นี่คือสิ่งที่โซลูชันทั้งสองข้างต้นส่งคืน: 1. ไฟล์: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 เพราะเป็นสิ่งที่แตกต่าง ฉันต้องการเนื้อหา: // format URI คำตอบจาก Jinal ดูเหมือนว่าจะทำงานได้อย่างสมบูรณ์
Ajith Memana

5
เฮ้Uri.fromFileจะไม่ทำงานบน Android 26+ คุณควรใช้ผู้ให้บริการไฟล์
vuhung3990

85

UPDATE

ที่นี่จะถือว่าสื่อของคุณ (รูปภาพ / วิดีโอ) ถูกเพิ่มไปยังผู้ให้บริการสื่อเนื้อหาแล้ว ถ้าไม่เช่นนั้นคุณจะไม่สามารถรับ URL เนื้อหาตามที่คุณต้องการได้ แต่จะมีไฟล์ Uri แทน

ฉันมีคำถามเดียวกันสำหรับกิจกรรมสำรวจไฟล์ของฉัน คุณควรรู้ว่า contenturi สำหรับไฟล์รองรับข้อมูล mediastore เช่นรูปภาพเสียงและวิดีโอเท่านั้น ฉันจะให้รหัสสำหรับรับเนื้อหาภาพ uri จากการเลือกภาพจาก sdcard ลองใช้รหัสนี้อาจใช้ได้กับคุณ ...

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

ฉันกำลังมองหาวิธีในการค้นหาเนื้อหา: // URI ของไฟล์วิดีโอที่บันทึกไว้และโค้ดด้านบนดูเหมือนว่าจะทำงานได้อย่างสมบูรณ์ใน Nexus 4 (Android 4.3) มันจะดีถ้าคุณสามารถอธิบายรหัสได้
Ajith Memana

ฉันได้ลองสิ่งนี้เพื่อรับ Content Uri สำหรับไฟล์ที่มีพา ธ สัมบูรณ์ "/ sdcard / Image Depo / picture.png" ไม่ทำงานดังนั้นฉันจึงดีบักพา ธ โค้ดและพบว่าเคอร์เซอร์ว่างเปล่าและเมื่อรายการถูกเพิ่มลงใน ContentProvider จะให้ null เป็น URI เนื้อหา กรุณาช่วย.
ศรีกฤษณะ

1
ฉันมีเส้นทางไฟล์ - ไฟล์: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4 แต่รับ null เมื่อฉันพยายามรับ contentUri ฉันพยายามเปลี่ยนMediaStore.Images.MediaไปMediaStore.Video.Mediaแต่ก็ยังไม่มีโชค
Narendra Singh

1
นี่ไม่ได้ทำงานกับ android Pie api 28 เคอร์เซอร์ส่งคืน null
Ibrahim Gharyali

1
คุณสามารถอัปเดตวิธีนี้สำหรับ Android 10 ได้หรือไม่เนื่องจากคอลัมน์ DATA ไม่สามารถเข้าถึงได้ใน Android 10
Khushbu Shah

16

// รหัสนี้ใช้ได้กับรูปภาพใน 2.2 ไม่แน่ใจว่าสื่อประเภทอื่น ๆ

   //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
เยี่ยมมากช่วยฉันด้วยการแชร์ Google+ เพราะแอพนั้นต้องการกระแสข้อมูลสื่อที่มีเนื้อหา Uri - เส้นทางแบบสัมบูรณ์ไม่ทำงาน
Ridcully

1
ยอดเยี่ยม ฉันสามารถยืนยันการใช้งานได้กับสื่อประเภทเสียงเช่นกัน
Matt M

16

ทางออกที่ได้รับการยอมรับน่าจะเป็นทางออกที่ดีที่สุดสำหรับคุณ แต่เพื่อตอบคำถามในหัวเรื่อง:

ในแอพของฉันฉันต้องรับพา ธ จาก URIs และรับ URI จากพา ธ อดีต:

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

อันหลัง (ซึ่งฉันทำกับวิดีโอ แต่ยังสามารถใช้สำหรับเสียงหรือไฟล์หรือเนื้อหาประเภทอื่นที่เก็บไว้ได้โดยการแทนที่ MediaStore.Audio (ฯลฯ ) สำหรับ MediaStore.Video):

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

โดยทั่วไปDATAคอลัมน์ของMediaStore(หรือส่วนย่อยที่คุณกำลังสอบถาม) จัดเก็บพา ธ ไฟล์ดังนั้นคุณจึงใช้ข้อมูลนั้นเพื่อค้นหา


ไม่เสมอไปมีการรับประกันสองคอลัมน์ที่ถูกส่งคืนและนั่นก็คือOpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEหากแอปที่ส่งเป็นไปตาม "กฎ" ฉันพบว่าแอพหลัก ๆ บางตัวจะส่งคืนทั้งสองฟิลด์เท่านั้นและไม่ได้เป็น_dataฟิลด์เสมอไป ในกรณีที่คุณไม่มีเขตข้อมูลซึ่งโดยปกติจะมีเส้นทางตรงไปยังเนื้อหาคุณต้องอ่านเนื้อหาก่อนและเขียนไปยังไฟล์หรือหน่วยความจำแล้วคุณมีเส้นทางของคุณเอง
Pierre

7

คุณสามารถใช้สองวิธีนี้ตามการใช้งาน

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

หรือ

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

ฉันลองทั้งสองวิธีและทั้งสองอย่างแล้ว


5

ที่ง่ายที่สุดและวิธีที่มีประสิทธิภาพสำหรับการสร้างเนื้อหา Uri content://จากแฟ้มคือการใช้FileProvider URI ที่จัดทำโดย FileProvider ยังสามารถใช้จัดหา Uri เพื่อแชร์ไฟล์กับแอปอื่น ๆ ได้อีกด้วย ในการรับ File Uri จากพา ธ สัมบูรณ์Fileคุณสามารถใช้ DocumentFile.fromFile (ไฟล์ใหม่ (พา ธ ชื่อ)) ได้รับการเพิ่มใน Api 22 และส่งคืน null สำหรับเวอร์ชันด้านล่าง

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

4

มันสาย แต่อาจช่วยใครบางคนในอนาคต

ในการรับ URI ของเนื้อหาสำหรับไฟล์คุณสามารถใช้วิธีการต่อไปนี้:

FileProvider.getUriForFile(Context context, String authority, File file)

ส่งคืน URI เนื้อหา

ลองใช้งานดูเพื่อเรียนรู้วิธีตั้งค่า FileProvider


2

การรับ ID ไฟล์โดยไม่ต้องเขียนโค้ดใด ๆ เพียงแค่ใช้คำสั่ง adb shell CLI:

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

Google "adb ได้รับเส้นทางที่แท้จริงจากเนื้อหา uri" และคำถามนี้อยู่บนสุด 1 ด้วยเนื้อหาของคำตอบ 0 คะแนนของคุณในสรุปผลการค้นหา ดังนั้นฉันจะเป็นคนแรกที่ลงคะแนน ขอบใจนะ!
วันหยุดสุดสัปดาห์

ที่นี่หนาว. แต่ดูเหมือนว่าคุณจะได้รับ: Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLYยกเว้นว่าคุณได้รับการรูท
not2qubit

ดังนั้นสิ่งนี้จึงจำเป็นต้องเข้าถึงรูทโทรศัพท์หรือไม่
Samintha Kaveesh

1

ดีกว่าที่จะใช้การตรวจสอบเพื่อรองรับรุ่นก่อน Android N ตัวอย่างเช่น:

  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

คุณสามารถลองดูตัวอย่างโค้ดด้านล่าง

    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 คืออะไร
Evgenii Vorobei

มันคือ "ภายนอก" หรือ "ภายใน"
caopeng
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.