Android中通过URI获取视频文件大小返回0问题求助
It’s common to run into issues with content URIs when trying to get file sizes on Android—here’s why your current approach isn’t working and how to fix it:
Why Your java.net.URI Approach Fails
When you get a video URI from the camera intent or gallery, it’s almost always a content URI (looks like content://media/external/video/media/XXX) rather than a direct file URI. A content URI points to media stored in the system’s MediaStore, not a physical file path that java.net.URI can resolve to a valid File object. That’s why you’re getting a size of 0—your code is trying to access a file that doesn’t exist at that "path."
Solution: Get Video Size Using ContentResolver
The correct way to retrieve the size of a video (whether from gallery or camera) is to use Android’s ContentResolver to query the MediaStore, or directly read from the URI if needed. Here’s how to implement this end-to-end:
1. Set Up Activity Result Handlers (Modern Approach)
First, use the Activity Result API (recommended for Android X and above) to handle video selection and recording:
// For picking video from gallery private ActivityResultLauncher<String> pickVideoLauncher; // For recording video with camera private ActivityResultLauncher<Uri> recordVideoLauncher; private File tempVideoFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize gallery pick launcher pickVideoLauncher = registerForActivityResult( new ActivityResultContracts.GetContent(), uri -> { if (uri != null) { long videoSize = getVideoSize(uri); checkVideoSizeLimit(videoSize); } }); // Initialize camera record launcher recordVideoLauncher = registerForActivityResult( new ActivityResultContracts.TakeVideo(), isSuccess -> { if (isSuccess && tempVideoFile != null) { // For camera-recorded video, get size directly from the temp file long videoSize = tempVideoFile.length(); checkVideoSizeLimit(videoSize); } }); }
2. Create Temporary File for Camera Recording
When using the camera intent, you need to provide a URI where the camera will save the video. Use FileProvider (to comply with scoped storage) to create a valid content URI:
private File createTempVideoFile() throws IOException { // Create a unique temporary file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String videoFileName = "VID_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES); return File.createTempFile(videoFileName, ".mp4", storageDir); } // Call this method to start recording private void startCameraRecording() { try { tempVideoFile = createTempVideoFile(); Uri videoUri = FileProvider.getUriForFile( this, "com.yourpackage.name.fileprovider", // Replace with your FileProvider authority tempVideoFile ); recordVideoLauncher.launch(videoUri); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "Failed to create temp file", Toast.LENGTH_SHORT).show(); } }
3. Implement the Video Size Calculation Method
This method handles both content URIs (from gallery) and file URIs (from camera temp file):
private long getVideoSize(Uri videoUri) { long size = 0; ContentResolver resolver = getContentResolver(); if (ContentResolver.SCHEME_CONTENT.equals(videoUri.getScheme())) { // Query MediaStore for the video size try (Cursor cursor = resolver.query( videoUri, new String[]{MediaStore.Video.Media.SIZE}, null, null, null )) { if (cursor != null && cursor.moveToFirst()) { size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)); } } catch (Exception e) { e.printStackTrace(); // Fallback: If query fails, read the input stream to get size try (InputStream inputStream = resolver.openInputStream(videoUri)) { if (inputStream != null) { size = inputStream.available(); } } catch (IOException ex) { ex.printStackTrace(); } } } else if (ContentResolver.SCHEME_FILE.equals(videoUri.getScheme())) { // Handle file URI (e.g., temp file from camera) File videoFile = new File(videoUri.getPath()); size = videoFile.length(); } return size; }
4. Check Size and Show Toast
Finally, add the logic to compare the size against your 5MB limit:
private void checkVideoSizeLimit(long videoSize) { final long MAX_VIDEO_SIZE = 5 * 1024 * 1024; // 5MB in bytes if (videoSize > MAX_VIDEO_SIZE) { Toast.makeText(this, "Video size exceeds 5MB", Toast.LENGTH_LONG).show(); } }
5. Required Setup for FileProvider
To use FileProvider, add this to your AndroidManifest.xml:
<application ...> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.yourpackage.name.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
Then create a res/xml/file_paths.xml file:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_movies" path="Movies/" /> </paths>
Key Notes
- Permissions: For camera recording, you’ll need to request the
CAMERApermission (andWRITE_EXTERNAL_STORAGEif targeting Android 9 or lower). - Scoped Storage: On Android 10+, direct file access is restricted, so using
ContentResolverorFileProvideris mandatory for accessing media files. - Fallback Logic: The
getContentResolver().openInputStream()fallback ensures you can get the size even if the MediaStore query fails (e.g., for videos stored in cloud providers).
This approach should correctly retrieve the video size every time, eliminating the 0 value you were seeing earlier.
内容的提问来源于stack exchange,提问作者Usman Khan

