Android получить реальный путь с помощью Uri.getPath () - PullRequest
89 голосов
/ 07 мая 2010

Я пытаюсь получить изображение из галереи.

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode );

После того, как я вернулся из этого занятия, у меня есть данные, которые содержат Uri. Похоже:

content://media/external/images/1

Как мне преобразовать этот путь в реальный (как '/sdcard/image.png')?

Спасибо

Ответы [ 8 ]

179 голосов
/ 03 апреля 2012

Вот что я делаю:

Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));

и

private String getRealPathFromURI(Uri contentURI) {
    String result;
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) { // Source is Dropbox or other similar local file path
        result = contentURI.getPath();
    } else { 
        cursor.moveToFirst(); 
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}

ПРИМЕЧАНИЕ: managedQuery() метод устарел, поэтому я его не использую.

Последнее редактирование: улучшение. Мы должны закрыть курсор !!

52 голосов
/ 07 мая 2010

Действительно ли вам необходимо получить физический путь?
Например, ImageView.setImageURI() и ContentResolver.openInputStream() позволяют вам получить доступ к содержимому файла, не зная его реального пути.

17 голосов
/ 12 октября 2015

@ Rene Juuse - выше в комментариях ... Спасибо за эту ссылку!

. код для получения реального пути немного отличается от одного SDK к другому, поэтому ниже у нас есть три метода, которые работают с разными SDK.

getRealPathFromURI_API19 (): возвращает реальный путь для API 19 (или выше, но не проверено) getRealPathFromURI_API11to18 (): возвращает реальный путь от API 11 до API 18 getRealPathFromURI_below11 (): возвращает реальный путь для API ниже 11

public class RealPathUtil {

@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
    String filePath = "";
    String wholeID = DocumentsContract.getDocumentId(uri);

     // Split at colon, use second item in the array
     String id = wholeID.split(":")[1];

     String[] column = { MediaStore.Images.Media.DATA };     

     // where id is equal to             
     String sel = MediaStore.Images.Media._ID + "=?";

     Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                               column, sel, new String[]{ id }, null);

     int columnIndex = cursor.getColumnIndex(column[0]);

     if (cursor.moveToFirst()) {
         filePath = cursor.getString(columnIndex);
     }   
     cursor.close();
     return filePath;
}


@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
      String[] proj = { MediaStore.Images.Media.DATA };
      String result = null;

      CursorLoader cursorLoader = new CursorLoader(
              context, 
        contentUri, proj, null, null, null);        
      Cursor cursor = cursorLoader.loadInBackground();

      if(cursor != null){
       int column_index = 
         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       result = cursor.getString(column_index);
      }
      return result;  
}

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
           String[] proj = { MediaStore.Images.Media.DATA };
           Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
           int column_index
      = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
           cursor.moveToFirst();
           return cursor.getString(column_index);
}

шрифт: http://hmkcode.com/android-display-selected-image-and-its-real-path/


ОБНОВЛЕНИЕ 2016 Март

Чтобы исправить все проблемы с путями к изображениям, я пытаюсь создать собственную галерею в виде facebook и других приложений. Это потому, что вы можете использовать только локальные файлы (реальные файлы, а не виртуальные или временные), я решаю все проблемы с этой библиотекой.

https://github.com/nohana/Laevatein (эта библиотека позволяет делать снимки с камеры или выбирать галерею, если вы выбираете из галереи у него ящик с альбомами и просто показывает локальные файлы)

14 голосов
/ 12 апреля 2016

Примечание Это улучшение @ user3516549 ответа , и я проверил его на Moto G3 с Android 6.0.1
У меня есть эта проблема, поэтому я попытался ответить на @ user3516549, но в некоторых случаях он не работал должным образом. Я обнаружил, что в Android 6.0 (или выше), когда мы запускаем намерение выбрать изображение галереи, откроется экран, который показывает последние изображения, когда пользователь выбирает изображение из этого списка, мы получим uri как

content://com.android.providers.media.documents/document/image%3A52530

в то время как если пользователь выберет галерею из выдвижного ящика вместо недавнего, тогда мы получим uri как

content://media/external/images/media/52530

Итак, я справлюсь с этим getRealPathFromURI_API19()

public static String getRealPathFromURI_API19(Context context, Uri uri) {
        String filePath = "";
        if (uri.getHost().contains("com.android.providers.media")) {
            // Image pick from recent 
            String wholeID = DocumentsContract.getDocumentId(uri);

            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];

            String[] column = {MediaStore.Images.Media.DATA};

            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";

            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{id}, null);

            int columnIndex = cursor.getColumnIndex(column[0]);

            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();
            return filePath;
        } else {
            // image pick from gallery 
           return  getRealPathFromURI_BelowAPI11(context,uri)
        }

    }

РЕДАКТИРОВАТЬ: , если вы пытаетесь получить путь к изображению файла на внешней SD-карте в более высокой версии, тогда проверьте мой вопрос

7 голосов
/ 19 мая 2017

Реального пути нет .

A Uri со схемой content является непрозрачным дескриптором некоторого содержимого. Если это Uri представляет открываемый контент, вы можете использовать ContentResolver и openInputStream(), чтобы получить InputStream для этого контента. Точно так же, Uri со схемой http или https не представляет локальный файл, и вам потребуется API-интерфейс HTTP-клиента для доступа к нему.

Только Uri со схемой file идентифицирует файл (за исключением случаев, когда файл был перемещен или удален после создания Uri).

Что глупые люди делают, так это пытаются найти путь к файловой системе, пытаясь декодировать содержимое Uri, возможно, в сочетании с заклинаниями для вызова $EVIL_DEITY. В лучшем случае это будет ненадежно по трем причинам:

  1. Правила декодирования значений Uri могут изменяться со временем, например, в версиях Android, поскольку структура Uri представляет подробности реализации, а не интерфейс

  2. Даже если вы получите путь к файловой системе, у вас может не быть прав доступа к файлу

  3. Не все значения Uri могут быть декодированы с помощью фиксированных алгоритмов, поскольку многие приложения имеют своих собственных провайдеров, и они могут указывать на все: от ресурсов до столбцов BLOB до данных, которые необходимо передавать из Интернета.

Если у вас есть ограниченный API, для которого требуется файл, используйте InputStream из openInputStream(), чтобы сделать копию этого содержимого. Является ли это временной копией (например, используемой для операции загрузки файла, затем удаленной) или долговременной копией (например, для функции «импорта» вашего приложения), остается за вами.

4 голосов
/ 27 ноября 2016

РЕДАКТИРОВАТЬ: Используйте это решение здесь: https://stackoverflow.com/a/20559175/2033223 Работает отлично!

Прежде всего, спасибо за ваше решение @ luizfelipetx

Я изменил ваше решениесовсем немного.Это работает для меня:

public static String getRealPathFromDocumentUri(Context context, Uri uri){
    String filePath = "";

    Pattern p = Pattern.compile("(\\d+)$");
    Matcher m = p.matcher(uri.toString());
    if (!m.find()) {
        Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString());
        return filePath;
    }
    String imgId = m.group();

    String[] column = { MediaStore.Images.Media.DATA };
    String sel = MediaStore.Images.Media._ID + "=?";

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            column, sel, new String[]{ imgId }, null);

    int columnIndex = cursor.getColumnIndex(column[0]);

    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }
    cursor.close();

    return filePath;
}

Примечание: Таким образом, мы получили документы и изображение, в зависимости от того, было ли изображение из «последних», «галереи» или чего-либо еще.Поэтому я сначала извлекаю идентификатор изображения, прежде чем искать его.

1 голос
/ 11 июля 2016

Hii Вот мой полный код для получения изображения с камеры или галереи

// Объявление моей переменной

protected static final int CAMERA_REQUEST = 0;
    protected static final int GALLERY_REQUEST = 1;
    Bitmap bitmap;
    Uri uri;
    Intent picIntent = null;

// Onclick

if (v.getId()==R.id.image_id){
            startDilog();
        }

//тело метода

private void startDilog() {
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this);
    myAlertDilog.setTitle("Upload picture option..");
    myAlertDilog.setMessage("Where to upload picture????");
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(Intent.ACTION_GET_CONTENT,null);
            picIntent.setType("image/*");
            picIntent.putExtra("return_data",true);
            startActivityForResult(picIntent,GALLERY_REQUEST);
        }
    });
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(picIntent,CAMERA_REQUEST);
        }
    });
    myAlertDilog.show();
}

// И все остальное

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==GALLERY_REQUEST){
        if (resultCode==RESULT_OK){
            if (data!=null) {
                uri = data.getData();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                try {
                    BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    options.inSampleSize = calculateInSampleSize(options, 100, 100);
                    options.inJustDecodeBounds = false;
                    Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    imageofpic.setImageBitmap(image);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        }else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            if (data.hasExtra("data")) {
                bitmap = (Bitmap) data.getExtras().get("data");
                uri = getImageUri(YourActivity.this,bitmap);
                File finalFile = new File(getRealPathFromUri(uri));
                imageofpic.setImageBitmap(bitmap);
            } else if (data.getExtras() == null) {

                Toast.makeText(getApplicationContext(),
                        "No extras to retrieve!", Toast.LENGTH_SHORT)
                        .show();

                BitmapDrawable thumbnail = new BitmapDrawable(
                        getResources(), data.getData().getPath());
                pet_pic.setImageDrawable(thumbnail);

            }

        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private String getRealPathFromUri(Uri tempUri) {
    Cursor cursor = null;
    try {
        String[] proj = { MediaStore.Images.Media.DATA };
        cursor = this.getContentResolver().query(tempUri,  proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}
public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

private Uri getImageUri(YourActivity youractivity, Bitmap bitmap) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null);
    return Uri.parse(path);
}
0 голосов
/ 06 июня 2017

Это помогло мне получить URI из галереи и преобразовать в файл для многочастной загрузки

File file = FileUtils.getFile(this, fileUri);

https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java

...