'Get file size using URI in android

I am working on android video application where I am recording a Video using Camera Intent and taking a video from gallery. When recording video or after selecting video from gallery I want to know the size of my video which I took. I want to make a logic to show a user a toast message if selected Video size is greater then 5MB. I made the bottom logic which is not working and giving me 0 value where I tried to take the size from URI.

Thanks in advance.

My Logic which is not working

java.net.URI juri = new java.net.URI(uri.toString());
        File mediaFile = new File(juri.getPath());
        long fileSizeInBytes = mediaFile.length();
        long fileSizeInKB = fileSizeInBytes / 1024;
        long fileSizeInMB = fileSizeInKB / 1024;

        if (fileSizeInMB > 5) {
            Toast.makeText(this,"Video files lesser than 5MB are allowed",Toast.LENGTH_LONG).show();
            return;
        }

This is my code which I am using to get video from Gallery and to record video.

public void takeVideoFromCamera(){

        File mediaFile =new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/myvideo.mp4");

        Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
        Uri videoUri;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//            videoUri = FileProvider.getUriForFile(this, this.getApplicationContext().getPackageName() + ".provider", mediaFile);
            videoUri = FileProvider.getUriForFile(this, "i.am.ce.by.ncy.provider", mediaFile);
        } else {
            videoUri  = Uri.fromFile(mediaFile);
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri);
        intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
        intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 5491520L);//5*1048*1048=5MB
        intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT,45);
        startActivityForResult(intent, VIDEO_CAPTURE);
    }

    public void takeVideoFromGallery(){
        Intent intent = new Intent();
        intent.setType("video/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        long maxVideoSize = 5 * 1024 * 1024; // 10 MB
        intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, maxVideoSize);
        startActivityForResult(Intent.createChooser(intent,"Select Video"),REQUEST_TAKE_GALLERY_VIDEO);

    }

onActivityResult code

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == this.RESULT_OK) {

            switch (requestCode) {
                case VIDEO_CAPTURE:
                        if (resultCode == RESULT_OK) {
                            showVideoImage(data.getData());
// Here I want to know what is the size of my Video File
                        } 
                    break;
                case REQUEST_TAKE_GALLERY_VIDEO:
                    if (resultCode == RESULT_OK) {
                        showVideoGallery(data);
// Here I want to know what is the size of my Video File
                    } 
                    break;
          }


Solution 1:[1]

  1. Checks AssetFileDescriptor.length
  2. If not found, checks ParcelFileDescriptor.getStatSize implicitly inside AssetFileDescriptor.length
  3. If not found, check MediaStore/ContentResolver if URI has content:// scheme

Should work for file://, content:// schemes. Returns -1L if failed to find:

fun Uri.length(contentResolver: ContentResolver)
        : Long {

    val assetFileDescriptor = try {
        contentResolver.openAssetFileDescriptor(this, "r")
    } catch (e: FileNotFoundException) {
        null
    }
    // uses ParcelFileDescriptor#getStatSize underneath if failed
    val length = assetFileDescriptor?.use { it.length } ?: -1L
    if (length != -1L) {
        return length
    }

    // if "content://" uri scheme, try contentResolver table
    if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
        return contentResolver.query(this, arrayOf(OpenableColumns.SIZE), null, null, null)
                ?.use { cursor ->
                    // maybe shouldn't trust ContentResolver for size: https://stackoverflow.com/questions/48302972/content-resolver-returns-wrong-size
                    val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
                    if (sizeIndex == -1) {
                        return@use -1L
                    }
                    cursor.moveToFirst()
                    return try {
                        cursor.getLong(sizeIndex)
                    } catch (_: Throwable) {
                        -1L
                    }
                } ?: -1L
    } else {
        return -1L
    }
}

Solution 2:[2]

AssetFileDescriptor fileDescriptor = getApplicationContext().getContentResolver().openAssetFileDescriptor(uri , "r");
long fileSize = fileDescriptor.getLength();

Solution 3:[3]

java.net.URI juri = new java.net.URI(uri.toString());
File mediaFile = new File(juri.getPath());

A Uri is not a File.

showVideoImage(data.getData());

ACTION_VIDEO_CAPTURE does not return a Uri.

Moreover, you already know where the file is. You create a File object in takeVideoFromCamera() and use that for EXTRA_OUTPUT. Hold onto that File object (and also save it in the saved instance state Bundle), then use that for finding out the size of the resulting video.

Solution 4:[4]

private long getFileSize(Uri fileUri) {
    Cursor returnCursor = getContentResolver().
            query(fileUri, null, null, null, null);
    int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
    returnCursor.moveToFirst();
    
    long size = returnCursor.getLong(sizeIndex);
    returnCursor.close();

    return size;
}

Check here for more details

Solution 5:[5]

This is working for me:

        Uri path = data.getData();
        Cursor returnCursor = getContentResolver().
                query(path, null, null, null, null);
        int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
        returnCursor.moveToFirst();

        int size = returnCursor.getInt(sizeIndex) / 1000;

        returnCursor.close();

        tv_description.setText("size: " + size);

You Can use getInt, getLong etc...

Solution 6:[6]

Following extension function supports 3 different URI types,

  1. Content URI content://document/primary:sample.png
  2. File URI file://data/user/0/com.example.testapp/cache/output.png
  3. Resource URI "android.resource://com.example.testapp/" + R.raw.sample
fun Uri.length(context: Context): Long {
    val fromContentProviderColumn = fun(): Long {
        // Try to get content length from the content provider column OpenableColumns.SIZE
        // which is recommended to implement by all the content providers
        var cursor: Cursor? = null
        return try {
            cursor = context.contentResolver.query(
                this,
                arrayOf(OpenableColumns.SIZE),
                null,
                null,
                null
            ) ?: throw Exception("Content provider returned null or crashed")
            val sizeColumnIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
            if (sizeColumnIndex != -1 && cursor.count > 0) {
                cursor.moveToFirst()
                cursor.getLong(sizeColumnIndex)
            } else {
                -1
            }
        } catch (e: Exception) {
            Log.d(TAG, e.message ?: e.javaClass.simpleName)
            -1
        } finally {
            cursor?.close()
        }
    }

    val fromFileDescriptor = fun(): Long {
        // Try to get content length from content scheme uri or file scheme uri
        var fileDescriptor: ParcelFileDescriptor? = null
        return try {
            fileDescriptor = context.contentResolver.openFileDescriptor(this, "r")
                ?: throw Exception("Content provider recently crashed")
            fileDescriptor.statSize
        } catch (e: Exception) {
            Log.d(TAG, e.message ?: e.javaClass.simpleName)
            -1
        } finally {
            fileDescriptor?.close()
        }
    }

    val fromAssetFileDescriptor = fun(): Long {
        // Try to get content length from content scheme uri, file scheme uri or android resource scheme uri
        var assetFileDescriptor: AssetFileDescriptor? = null
        return try {
            assetFileDescriptor = context.contentResolver.openAssetFileDescriptor(this, "r")
                ?: throw Exception("Content provider recently crashed")
            assetFileDescriptor.length
        } catch (e: Exception) {
            Log.d(TAG, e.message ?: e.javaClass.simpleName)
            -1
        } finally {
            assetFileDescriptor?.close()
        }
    }

    return when (scheme) {
        ContentResolver.SCHEME_FILE -> {
            fromFileDescriptor()
        }
        ContentResolver.SCHEME_CONTENT -> {
            val length = fromContentProviderColumn()
            if (length >= 0) {
                length
            } else {
                fromFileDescriptor()
            }
        }
        ContentResolver.SCHEME_ANDROID_RESOURCE -> {
            fromAssetFileDescriptor()
        }
        else -> {
            -1
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jemshit Iskenderov
Solution 2 Markus Rollmann
Solution 3 CommonsWare
Solution 4 EpicPandaForce
Solution 5 EpicPandaForce
Solution 6 UdaraWanasinghe