Search code examples
androidandroid-contentresolver

Android _data' does not exist on getContentResolver


What might the cause of getColumnIndexOrThrow that would throw an exception of

java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: []

yet if you rename the file and retry again, it works?

private static String getDataColumn(Context context, Uri uri, String selection,
                                       String[] selectionArgs) {
        Cursor cursor = null;
        final String[] projection = {
                MediaStore.Files.FileColumns.DATA
        };
        try {
            cursor = context.getContentResolver().query(
                    uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int cindex = cursor.getColumnIndexOrThrow(projection[0]);
                return cursor.getString(cindex);
            }
        }
             catch (Exception e) {
                e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

the original file comes in the intent of

content://com.sec.android.app.myfiles.FileProvider/device_storage/Download/myfile.pdf

yet the renamed file comes in as

content://0@media/external/file/588


Solution

  • This MediaStore.Files.FileColumns.DATA is deprecated and column '_data' doesn't exist anymore.

    As Android Developer stated

    This constant was deprecated in API level 29.

    Apps may not have filesystem permissions to directly access this path. Instead of trying to open this path directly, apps should use ContentResolver#openFileDescriptor(Uri, String) to gain access.

    How To use openFileDescriptor?

    i try to bring examples of 2 different widely use files in across application

    Image Files

    if(uri==null)return;
    ContentResolver contentResolver = getActivity().getContentResolver();
    if(contentResolver==null)return;
    ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor(uri,"rw");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    if(fileDescriptor==null)return;
    Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    parcelFileDescriptor.close();
    

    There are a lot of examples of how to handle bitmap

    Non-Image Files

    if(uri==null)return;
    ContentResolver contentResolver = getActivity().getContentResolver();
    if(contentResolver==null)return;
    ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor(uri,"rw");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    if(fileDescriptor==null)return;
    FileInputStream fileInputStream = new FileInputStream(fileDescriptor);
    FileOutputStream fileOutputStream = new FileOutputStream(fileDescriptor);
    parcelFileDescriptor.close();
    

    There are a lot of examples of how to handle FileInputStream and FileOutputStream

    Conclusion

    There is no sense trying to get absolute Path although it isn't necessary unless raising security & privacy issues.Indeed, Relative path is enough for working with files and there are Abstract Representation implementations between kernel Mode and User Mode that can Map Relative Path to Absolute Path and User doesn't need to know.

    openFileDescriptor is very fast and compatible to all android versions