43

In an Activity, I can choose an image from the Gallery, and I need its Uri path (in the log, the Uri path for my test image is /content:/media/external/images/media/1).

I'm getting this error though:

08-04 02:14:21.912: DEBUG/PHOTOUPLOADER(576): java.io.FileNotFoundException: /content:/media/external/images/media/1 (No such file or directory)
08-04 02:14:32.124: WARN/System.err(576): java.io.FileNotFoundException: /content:/media/external/images/media/1 (No such file or directory)

Is this the correct format of a file path? Or should I make it to be something like sdcard\...\image.png?

RominaV
  • 3,335
  • 1
  • 29
  • 59
Allan Jiang
  • 11,063
  • 27
  • 104
  • 165

4 Answers4

45
val inputStream = context.contentResolver.openInputStream(uri)

is all you need.

Saket
  • 2,945
  • 1
  • 29
  • 31
  • 3
    How on earth this answer hasn't got any up votes yet? This is EXACTLY ALL WHAT WE NEED. Thank you Sir! – Woland Sep 10 '17 at 17:27
  • This is too easy. Does it only work for certain SDK versions or something? – Big McLargeHuge Apr 18 '19 at 13:31
  • 1
    @DavidKennedy `ContentResolver#openInputStream()` was added in API level 1 so don't think so – Saket Apr 19 '19 at 18:38
  • 1
    great, but how do i get path from this InputStream? – whereismaxmax Mar 31 '20 at 12:46
  • 1
    @whereismaxmax you don't, the idea is to abstract away file paths – Saket Jun 16 '20 at 20:01
  • 1
    Now I just need to get a file path from this. Might be able to convert InputStream to OutputStream and save the file to a different location (I need to copy it anyway). IMO this whole Uri business is ridiculous. Why return this useless abstract Uri thing from an Image Gallery Picker, rather than an actual path to the actual file, on the actual device? LIke real world stuff. Crazy I know – clamum Mar 19 '22 at 08:35
  • @clamum Android uses Uri instead of raw file paths because images picked from Android's media picker may not actually be stored on user's storage (think Dropbox or Google Photos for example). Just because you don't understand something fully doesn't make it ridiculous. – Saket Mar 20 '22 at 06:11
  • @Saket Yeah that's a good point, but the hoops you have to jump through for this are pretty funny. So it's impossible for a Uri to provide an absolute path if it's not a remote file? I just wish it wasn't so unwieldy to deal with. – clamum Mar 20 '22 at 09:49
  • I don't think it is. You get a URI whose content can be read using a couple lines of code, especially with Okio. Accessing raw paths was always dangerous because they can be cached longer than their files' lifetime. What happens if a file is deleted? If you really want file paths, copying them to your app storage is a safe solution. – Saket Mar 21 '22 at 03:26
45
public String getPath(Uri uri) {
    String[] projection = { MediaStore.Images.Media.DATA };
    Cursor cursor = managedQuery(uri, projection, null, null, null);
    startManagingCursor(cursor);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
Allan Jiang
  • 11,063
  • 27
  • 104
  • 165
  • 2
    For anyone else who gets here, note that managedQuery is a method of an activity, so you may need to provide an activity. – bugfixr Feb 29 '12 at 13:55
  • 1
    A second note is that the cursor should be closed `cursor.close()` – bugfixr Feb 29 '12 at 13:56
  • 3
    from the docs: Warning: Do not call Cursor.close() on a cursor obtained using this method, because the activity will do that for you at the appropriate time. – Keith Mar 26 '12 at 21:25
  • 12
    I would like to mention that `managedQuery` is now deprecated. If somebody developes the app for Android API 4 and higher, add support library v4 and use this code: `CursorLoader loader = new CursorLoader(context, uri, projection, null, null, null); Cursor cursor = loader.loadInBackground();` instead of `Cursor cursor = managedQuery(uri, projection, null, null, null);` – lomza Jun 12 '12 at 12:05
  • cursorloader target api 11 (at least for me) – D4rWiNS Aug 09 '13 at 07:20
  • crash when you pick an old picture from "Photos" – desgraci Mar 12 '14 at 22:35
  • I get the absolute uri but when I check the file.length() it's 0. Someone has one idea why? – FlavienBert Mar 17 '14 at 21:28
  • not compatible with all sdks , try my answer ... its full . – mhdjazmati Feb 17 '17 at 20:29
  • 3
    `MediaStore.Images.Media.DATA` is also deprecated, this method will no longer work – Kyle R Aug 26 '20 at 00:35
8

this works for all SDK's Versions :

/**
 * Get a file path from a Uri. This will get the the path for Storage Access
 * Framework Documents, as well as the _data field for the MediaStore and
 * other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @author paulburke
 */
public static String getPath(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }

            // TODO handle non-primary volumes
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

/**
 * Get the value of the data column for this Uri. This is useful for
 * MediaStore Uris, and other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @param selection (Optional) Filter used in the query.
 * @param selectionArgs (Optional) Selection arguments used in the query.
 * @return The value of the _data column, which is typically a file path.
 */
public static String getDataColumn(Context context, Uri uri, String selection,
        String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}


/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

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

mhdjazmati
  • 4,152
  • 1
  • 26
  • 37
0

try {

                 // open a URL connection to the Servlet
               FileInputStream fileInputStream = new FileInputStream(sourceFile);
               URL url = new URL(upLoadServerUri);

               // Open a HTTP  connection to  the URL
               conn = (HttpURLConnection) url.openConnection();
               conn.setDoInput(true); // Allow Inputs
               conn.setDoOutput(true); // Allow Outputs
               conn.setUseCaches(false); // Don't use a Cached Copy
               conn.setRequestMethod("POST");
               conn.setRequestProperty("Connection", "Keep-Alive");
               conn.setRequestProperty("ENCTYPE", "multipart/form-data");
               conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
               conn.setRequestProperty("uploaded_file", fileName);

               dos = new DataOutputStream(conn.getOutputStream());

               dos.writeBytes(twoHyphens + boundary + lineEnd);
               dos.writeBytes("Content-Disposition: form-data; name=uploaded_file;filename="+ fileName + "" + lineEnd);

               dos.writeBytes(lineEnd);

               // create a buffer of  maximum size
               bytesAvailable = fileInputStream.available();

               bufferSize = Math.min(bytesAvailable, maxBufferSize);
               buffer = new byte[bufferSize];

               // read file and write it into form...
               bytesRead = fileInputStream.read(buffer, 0, bufferSize); 

               while (bytesRead > 0) {

                 dos.write(buffer, 0, bufferSize);
                 bytesAvailable = fileInputStream.available();
                 bufferSize = Math.min(bytesAvailable, maxBufferSize);
                 bytesRead = fileInputStream.read(buffer, 0, bufferSize); 

                }

               // send multipart form data necesssary after file data...
               dos.writeBytes(lineEnd);
               dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

               // Responses from the server (code and message)
               serverResponseCode = conn.getResponseCode();
               String serverResponseMessage = conn.getResponseMessage();

               Log.i("uploadFile", "HTTP Response is : "
                       + serverResponseMessage + ": " + serverResponseCode);

               if(serverResponseCode == 200){

                   runOnUiThread(new Runnable() {
                        public void run() {

                            String msg = "File Upload Completed.\n\n See uploaded file here : \n\n"
                                          +" http://www.androidtrainer.netne.net.com/uploads/"
                                          +uploadFileName;

                            messageText.setText(msg);
                            Toast.makeText(UploadToServer.this, "File Upload Complete.",
                                         Toast.LENGTH_SHORT).show();
                        }
                    });               
               }   

               //close the streams //
               fileInputStream.close();
               dos.flush();
               dos.close();

          } catch (MalformedURLException ex) {

              dialog.dismiss(); 
              ex.printStackTrace();

              runOnUiThread(new Runnable() {
                  public void run() {
                      messageText.setText("MalformedURLException Exception : check script url.");
                      Toast.makeText(UploadToServer.this, "MalformedURLException",
                                                          Toast.LENGTH_SHORT).show();
                  }
              });

              Log.e("Upload file to server", "error: " + ex.getMessage(), ex); 
          } catch (Exception e) {

              dialog.dismiss(); 
              e.printStackTrace();

              runOnUiThread(new Runnable() {
                  public void run() {
                      messageText.setText("Got Exception : see logcat ");

if you have problem not solve till you can visit here for complete example