wubwubnoobnoob
wubwubnoobnoob

Reputation: 25

Get real path by Uri for any type of file

Here's what I would like to do in my app:

So I'd like to get real path to file and store it. The user will only be allowed to get files from internal/external storage so, as I assume, the real path will always exist. I've been looking for solutions and pretty much everyone asks only about images/audio/video and uses MediaStore in their solutions (and I, as of now, have no idea what this is, and I can get Uri without using it). I'd like a solution that would work with any type of file, if that's possible.

Here's how I'm getting Uri:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("*/*");
startActivityForResult(Intent.createChooser(intent, "Choose File"), 1);

and I'm storing the received information in onActivityResult method.

So i get Uri and store it as a string which looks like, for example, content://com.android.providers.downloads.documents/document/4588. How do I convert it to a real filepath?

Upvotes: 0

Views: 1471

Answers (2)

karandeep singh
karandeep singh

Reputation: 2334

Sharing my Fileutils file from one of my projects

public class FileUtils {

public static String getFilePath(Context context, Uri uri) throws URISyntaxException {
    String selection = null;
    String[] selectionArgs = null;
    // Uri is different in versions after KITKAT (Android 4.4), we need to
    if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context
            .getApplicationContext(), uri)) {
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            return Environment.getExternalStorageDirectory() + "/" + split[1];
        } else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            uri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
        } else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            if ("image".equals(type)) {
                uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }
            selection = "_id=?";
            selectionArgs = new String[]{
                    split[1]
            };
        } else if (isGoogleDriveFile(uri)) {
            String mimeType = context.getContentResolver().getType(uri);
            Cursor returnCursor =
                    context.getContentResolver().query(uri, null, null, null, null);
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
            returnCursor.moveToFirst();
            String fileName = returnCursor.getString(nameIndex);
            Log.d("name", returnCursor.getString(nameIndex));
            Log.d("size", Long.toString(returnCursor.getLong(sizeIndex)));
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);

                File root = new File(Environment.getExternalStorageDirectory(), "WittyParrot");
                root.mkdirs();
                File file = new File(root, fileName);
                copyStreamToFile(file, inputStream);
                return Uri.fromFile(file).getPath();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } finally {
                returnCursor.close();

            }

        }
    }

    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String[] projection = {
                MediaStore.Images.Media.DATA
        };
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver()
                    .query(uri, projection, selection, selectionArgs, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            if (cursor.moveToFirst()) {
                return cursor.getString(column_index);
            }
        } catch (Exception e) {
        }
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}

public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

public static boolean isGoogleDriveFile(Uri uri) {
    return "com.google.android.apps.docs.storage".equals(uri.getAuthority());
}

public static void copyStreamToFile(File file, InputStream input) {
    try {
        OutputStream output = new FileOutputStream(file);
        try {
            byte[] buffer = new byte[4 * 1024]; // or other buffer size
            int read;

            while ((read = input.read(buffer)) != -1) {
                output.write(buffer, 0, read);
            }

            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            output.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
}

Upvotes: 2

CommonsWare
CommonsWare

Reputation: 1007534

The user will only be allowed to get files from internal/external storage

Not according to your code. The user can use anything that supports ACTION_GET_CONTENT. There is no requirement for ACTION_GET_CONTENT implementations to be limited to external storage, and you cannot access internal storage from other apps using the filesystem.

If you are only willing to work with external storage, use a file chooser library, not ACTION_GET_CONTENT or ACTION_OPEN_DOCUMENT.

I'd like a solution that would work with any type of file, if that's possible.

Use a file chooser library.

How do I convert it to a real filepath?

You don't.

Upvotes: 0

Related Questions