Nhận nội dung uri từ đường dẫn tệp trong Android


271

Tôi biết đường dẫn tuyệt đối của một hình ảnh (ví dụ: /sdcard/cats.jpg). Có cách nào để có được nội dung uri cho tập tin này không?

Thực tế trong mã của tôi, tôi tải xuống một hình ảnh và lưu nó ở một vị trí cụ thể. Để đặt hình ảnh trong một phiên bản ImageView, hiện tại tôi mở tệp bằng đường dẫn, lấy các byte và tạo một bitmap và sau đó đặt bitmap trong đối tượng ImageView. Đây là một quá trình rất chậm, thay vào đó nếu tôi có thể có được nội dung uri thì tôi có thể dễ dàng sử dụng phương pháp này imageView.setImageUri(uri)


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

13
+1 cho nhận xét, chỉ cần Uri.parse ("tệp: //" + filePath) nên thực hiện thủ thuật
German Latorre

Uri.Pude bị khấu hao và "được thêm vào"
pollaris

@pollaris Uri.parse đã được thêm vào API 1 và nó không được đánh dấu cho sự phản đối.
JP de la Torre

Uri.parse ("cái gì đó"); không hoạt động với tôi, tôi không thể tìm thấy lý do tại sao ...
Bay

Câu trả lời:


480

Hãy thử với:

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

Hoặc với:

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

3
cảm ơn! phương pháp thứ hai hoạt động tốt trên 1.6, 2.1 và 2.2 nhưng phương thức thứ nhất chỉ trên 2.2
mishkin

28
cả hai phương thức này đều không giải quyết được đường dẫn tệp tới URI nội dung. tôi hiểu rằng nó đã giải quyết vấn đề ngay lập tức.
Jeffrey Blattman

38
Không mã hóa cứng "/ sdcard /"; sử dụng Môi
trường.getExternalStorageDirectory

8
Đây là những gì cả hai giải pháp trên trả về: 1. file: /// st Storage / emulation / 0 / DCIM /Camera / VID_20140312_171146.mp4 2. /st Storage / emulation / 0 / DCIM /Camera / VID_20140312_171146.mp4 Nhưng những gì tôi đang tìm kiếm cho là một cái gì đó khác nhau. Tôi cần nội dung: // định dạng URI. Câu trả lời từ Jinal dường như hoạt động hoàn hảo
Ajith Memana

5
hey Uri.fromFilesẽ không hoạt động trên Android 26+, bạn nên sử dụng nhà cung cấp tệp
vuhung3990

85

CẬP NHẬT

Ở đây, giả định rằng phương tiện của bạn (Hình ảnh / Video) đã được thêm vào nhà cung cấp phương tiện nội dung. Nếu không thì bạn sẽ không thể có được URL nội dung chính xác như những gì bạn muốn. Thay vào đó sẽ có tập tin Uri.

Tôi đã có cùng một câu hỏi cho hoạt động thám hiểm tập tin của tôi. Bạn nên biết rằng contenturi cho tệp chỉ hỗ trợ dữ liệu trung gian như hình ảnh, âm thanh và video. Tôi sẽ cung cấp cho bạn mã để nhận uri nội dung hình ảnh từ việc chọn một hình ảnh từ sdcard. Hãy thử mã này, có thể nó sẽ hoạt động cho bạn ...

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

Tôi đang tìm kiếm một phương pháp để tìm nội dung: // URI của tệp video đã ghi của tôi và đoạn mã trên dường như hoạt động hoàn hảo trên Nexus 4 (Android 4.3). Sẽ thật tốt nếu bạn có thể vui lòng giải thích mã.
Ajith Memana

Tôi đã thử cách này để lấy Uri nội dung cho một tệp có đường dẫn tuyệt đối "/ sdcard / Image Depo / image.png". Nó không hoạt động, vì vậy tôi đã gỡ lỗi đường dẫn mã và thấy rằng Con trỏ trống và khi mục nhập đang được thêm vào ContentProvider, nó sẽ không có giá trị như Content Uri. Xin vui lòng giúp đỡ.
Sri Krishna

1
Tôi có đường dẫn tệp - tệp: /// st Storage / emulation / 0 / Android / data / com.packagename / files / out.mp4, nhưng nhận được null khi tôi cố gắng lấy contentUri. Tôi cũng đã thử đổi MediaStore.Images.Mediasang MediaStore.Video.Media, nhưng vẫn không gặp may.
Narendra Singh

1
Điều này không hoạt động trên Android Pie api 28. Con trỏ trả về null
Ibrahim Gharyali

1
Bạn có thể cập nhật phương pháp này cho Android 10 vì cột DATA không thể truy cập được trong Android 10 không?
Khushbu Shah

16

// Mã này hoạt động cho hình ảnh trên 2.2, không chắc có loại phương tiện nào khác không

   //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
thật tuyệt, đã giúp tôi chia sẻ lên Google+, vì ứng dụng đó yêu cầu một luồng phương tiện có nội dung Uri - đường dẫn tuyệt đối không hoạt động.
Vô lý

1
Thông minh! Tôi có thể xác nhận điều này hoạt động với các loại phương tiện Audio.
Matt M

16

Giải pháp được chấp nhận có lẽ là đặt cược tốt nhất cho mục đích của bạn, nhưng để thực sự trả lời câu hỏi trong dòng chủ đề:

Trong ứng dụng của mình, tôi phải lấy đường dẫn từ URI và lấy URI từ đường dẫn. Các cựu:

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

Cái sau (tôi làm cho video, nhưng cũng có thể được sử dụng cho Audio hoặc Files hoặc các loại nội dung được lưu trữ khác bằng cách thay thế MediaStore.Audio (vv) cho 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;
}

Về cơ bản, DATAcột của MediaStore(hoặc bất kỳ phần phụ nào của nó bạn đang truy vấn) lưu trữ đường dẫn tệp, vì vậy bạn sử dụng thông tin đó để tra cứu nó.


Không phải lúc nào cũng vậy, có hai cột được bảo đảm bán lại và đó là OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEnếu ứng dụng gửi thậm chí tuân theo "quy tắc". Tôi thấy rằng một số ứng dụng chính chỉ trả về hai trường này và không phải luôn luôn là _datatrường. Trong trường hợp bạn không có trường dữ liệu thường chứa đường dẫn trực tiếp đến nội dung, trước tiên bạn phải đọc nội dung và ghi nó vào một tệp hoặc vào bộ nhớ và sau đó bạn có đường dẫn của riêng mình.
Pierre

7

Bạn có thể sử dụng hai cách này dựa trên việc sử dụng

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

hoặc là

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

Tôi đã thử cả hai cách và cả hai hoạt động.


5

Cách dễ nhất và mạnh mẽ để tạo Content Uri content://từ Tệp là sử dụng FileProvider . Uri do FileProvider cung cấp cũng có thể được sử dụng cũng cung cấp Uri để chia sẻ tệp với các ứng dụng khác. Để lấy File Uri từ một đường dẫn tuyệt đối, Filebạn có thể sử dụng DocumentFile.fromFile (Tệp mới (đường dẫn, tên)), nó được thêm vào Api 22 và trả về null cho các phiên bản bên dưới.

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


2

Lấy ID tệp mà không cần viết bất kỳ mã nào, chỉ với các lệnh CLI shell adb:

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

Google "adb có được đường dẫn thực sự từ nội dung uri" và câu hỏi này là top 1, với nội dung câu trả lời 0 phiếu của bạn trong bản tóm tắt kết quả tìm kiếm. Vì vậy, hãy để tôi là người đầu tiên bỏ phiếu. Cảm ơn người anh em!
Cuối tuần

Điều này thật tuyệt Nhưng có vẻ như bạn sẽ nhận được : Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, trừ khi bạn đã root.
not2qubit

Vì vậy, điều này không cần quyền truy cập root của điện thoại?
Samintha Kaveesh

1

Tốt hơn là sử dụng xác nhận để hỗ trợ các phiên bản trước Android N, ví dụ:

  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

Bạn có thể thử đoạn mã dưới đây

    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 là gì?
Evgenii Vorobei

Đó là "bên ngoài" hoặc "nội bộ"
caopeng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.