Android中如何合规读取外部存储视频文件信息?
Android存储权限与文件访问合规解决方案
问题场景代码
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private List<AssistInfo> assistInfos; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String filePath1 = "/storage/emulated/0/Movies/RoveDashCam/Rove-R24K-PRO/Videos/2023_0327_174047_0005.MP4"; String filePath2 = getFilesDir().getPath()+"/2023_0322_205825_0019.MP4"; if(new File(filePath1).exists()){ assistInfos = MP4Help.checkPlatform(filePath1); for (int i = 0; i <assistInfos.size() ; i++) { AssistInfo assistInfo = assistInfos.get(i); Log.d(TAG, assistInfo.getGps_lat()+","+assistInfo.getGps_lgt()+","+assistInfo.getSpd()); } } } }
问题背景
上述代码中,filePath1为外部存储公共目录路径,filePath2为应用内部私有存储路径:
- 使用
filePath1时,即便申请了常规外部存储读写权限,也无法通过指定的MP4Help库获取文件信息;仅申请MANAGE_EXTERNAL_STORAGE权限可正常访问,但该权限会导致应用被Google Play商店拒绝。 - 使用
filePath2无需任何权限即可正常访问文件内容。
技术解决方案
1. 合规获取外部存储中的文件信息
针对不同场景采用对应合规方案:
- 应用私有外部存储:文件存放在
getExternalFilesDir()或getExternalCacheDir()目录下时,无需额外权限,直接通过File类访问即可,此区域属于应用私有范围,系统允许直接操作。 - 公共媒体目录文件:
- Android 13+:申请对应媒体类型权限(如
READ_MEDIA_VIDEO),即可通过Media StoreAPI查询或访问视频文件; - Android 10~12:申请
READ_EXTERNAL_STORAGE权限,该权限为常规权限,不会触发Google Play审核拒绝;
- Android 13+:申请对应媒体类型权限(如
- 非媒体类公共文件:引导用户通过系统文件选择器(
ACTION_OPEN_DOCUMENT)获取文件URI,再通过ContentResolver访问文件内容,无需申请存储权限。
2. 读写内部存储中的大文件
内部存储为应用私有目录,无需权限,处理大文件核心是避免内存溢出,采用流式操作:
- 流式读取:使用
BufferedInputStream逐块读取文件,示例代码:
public void readLargeFile(String filePath) { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath))) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = bis.read(buffer)) != -1) { // 处理读取到的字节块,比如解析MP4信息 } } catch (IOException e) { Log.e(TAG, "Read file error", e); } }
- 流式写入:使用
BufferedOutputStream逐块写入,避免一次性加载大文件到内存; - 随机读写:若只需操作文件部分内容,使用
RandomAccessFile定位到指定位置读写,节省内存开销。
3. 通过Media Store API读取文件信息(无需特殊权限)
通过Media Store API可合规访问公共媒体文件,无需MANAGE_EXTERNAL_STORAGE权限,步骤如下:
- 查询媒体文件:通过
ContentResolver查询对应媒体类型的URI(视频文件用MediaStore.Video.Media.EXTERNAL_CONTENT_URI),获取目标文件的ContentUris; - 获取文件流:通过
ContentResolver.openInputStream()获取文件输入流,若MP4Help库仅支持文件路径,可将流复制到应用内部临时文件,再传入临时文件路径处理;
示例代码:
public void queryVideoInfo(Context context, String fileName) { String[] projection = { MediaStore.Video.Media._ID, MediaStore.Video.Media.DISPLAY_NAME }; String selection = MediaStore.Video.Media.DISPLAY_NAME + " = ?"; String[] selectionArgs = {fileName}; Cursor cursor = context.getContentResolver().query( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null ); if (cursor != null && cursor.moveToFirst()) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)); Uri videoUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id); // 获取文件流并复制到内部临时文件 try (InputStream is = context.getContentResolver().openInputStream(videoUri)) { File tempFile = new File(context.getCacheDir(), "temp.mp4"); try (OutputStream os = new FileOutputStream(tempFile)) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } } // 用临时文件路径调用MP4Help assistInfos = MP4Help.checkPlatform(tempFile.getAbsolutePath()); // 处理完成后删除临时文件 tempFile.delete(); } catch (IOException e) { Log.e(TAG, "Process video error", e); } cursor.close(); } }
- 若用户通过文件选择器选择文件,直接使用返回的
URI调用openInputStream()即可,无需申请任何存储权限。
内容的提问来源于stack exchange,提问作者MARSH
相关产品推荐
相关产品推荐

