Xamarin Android中使用BufferedStream读取文件遇权限拒绝求助
Xamarin Android模拟FilePicker缓存文件解决权限拒绝问题
问题根源
Android 10及以上启用了分区存储机制,直接通过绝对路径访问公共目录(比如Download)的文件,即便在清单中声明读写权限,也会触发权限拒绝。而FilePicker.PickAsync()是通过系统文件选择器获取文件的Content URI,再将文件复制到应用私有缓存目录——应用对私有目录拥有完全访问权限,因此不会出现权限问题。
模拟缓存行为的实现步骤
1. 获取文件的Content URI
可以通过系统文件选择器Intent或继续使用FilePicker.PickAsync()获取:
// 方式1:用FilePicker获取文件 var pickResult = await FilePicker.PickAsync(new PickOptions { PickerTitle = "选择目标文件" }); if (pickResult != null) { var fileUri = pickResult.FileUri; // 后续执行复制操作 } // 方式2:用系统Intent唤起文件选择器 Intent pickIntent = new Intent(Intent.ActionGetContent); pickIntent.SetType("*/*"); pickIntent.AddCategory(Intent.CategoryOpenable); StartActivityForResult(Intent.CreateChooser(pickIntent, "选择文件"), 100); // 在OnActivityResult中接收返回的URI protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (requestCode == 100 && resultCode == Result.Ok && data != null) { var fileUri = data.Data; // 后续执行复制操作 } }
2. 将文件复制到应用私有缓存目录
应用私有缓存目录可通过Context.CacheDir获取,无需额外权限即可访问:
private async Task<string> CopyToCache(Android.Net.Uri sourceUri) { // 生成唯一缓存文件名,避免冲突 var cacheFileName = $"cache_{Guid.NewGuid()}.pdf"; var cacheFilePath = Path.Combine(CacheDir.AbsolutePath, cacheFileName); // 从URI读取流并复制到缓存文件 using (var inputStream = ContentResolver.OpenInputStream(sourceUri)) using (var outputStream = new FileStream(cacheFilePath, FileMode.Create)) { await inputStream.CopyToAsync(outputStream); } return cacheFilePath; }
3. 从缓存目录读取文件
拿到缓存路径后,即可正常使用BufferedStream读取:
// 假设已获取到fileUri var cachePath = await CopyToCache(fileUri); using (var reader = new BufferedStream(File.OpenRead(cachePath))) { // 执行文件读取逻辑 }
额外提示
- 缓存文件不会自动清理,建议在操作完成或应用退出时删除,避免占用存储空间:
if (File.Exists(cachePath)) { File.Delete(cachePath); }
- 处理大文件时,建议分块复制,避免内存溢出。
内容的提问来源于stack exchange,提问作者vahid
相关产品推荐
相关产品推荐

