You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin中如何从外部SD卡的URI获取文件路径?

嘿,我懂你现在的困境——刚上手Xamarin Android,本来用ActionOpenDocumentTree选了保存路径,结果返回的URI里存储卷是12FB-3215(SD卡的UUID)而不是内置存储的primary,原来的文件选择器代码没处理这种情况,直接卡壳了对吧?别慌,我给你梳理几个解决思路:

处理Xamarin Android中非Primary存储的DocumentTree URI

首先得明白这个URI的结构:content://com.android.externalstorage.documents/tree/12FB-3215%3ATest 里的12FB-3215是外部SD卡的唯一标识符(UUID),%3ATest是转义后的文件夹路径(冒号+Test文件夹),和内置存储的primary是不同的存储卷标识。

1. 适配UUID类型的存储卷判断

原来的代码大概率只判断了type == "primary",现在把UUID的情况也加进去就行:

// 解析返回的Tree URI
var selectedTreeUri = Android.Net.Uri.Parse("content://com.android.externalstorage.documents/tree/12FB-3215%3ATest");
var docId = DocumentsContract.GetTreeDocumentId(selectedTreeUri);
// 拆分出存储卷类型和相对路径
var splitParts = docId.Split(new[] { ':' }, 2);
var storageType = splitParts[0];
var folderRelativePath = splitParts[1];

string storageRootPath = string.Empty;
// 处理内置存储
if (storageType.Equals("primary", StringComparison.OrdinalIgnoreCase))
{
    storageRootPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
}
// 处理SD卡UUID的情况
else
{
    var allStorageVolumes = Android.OS.Environment.GetExternalStorageVolumes();
    foreach (var volume in allStorageVolumes)
    {
        if (volume.Uuid?.Equals(storageType, StringComparison.OrdinalIgnoreCase) == true)
        {
            storageRootPath = volume.Directory?.AbsolutePath;
            break;
        }
    }
}

// 拼接成完整的物理路径
var fullFolderPath = Path.Combine(storageRootPath, folderRelativePath);

2. 权限与更安全的文件操作方式

在Android 10及以上的分区存储模式下,直接拿物理路径可能会遇到访问权限问题,更推荐用SAF自带的DocumentFile来操作文件,不需要纠结物理路径:

// 从Tree URI获取可操作的DocumentFile
var targetDirectory = DocumentFile.FromTreeUri(this, selectedTreeUri);
if (targetDirectory != null && targetDirectory.IsDirectory)
{
    // 比如在选中的目录下创建一个测试文本文件
    var newTestFile = targetDirectory.CreateFile("text/plain", "MyTestFile.txt");
    // 写入内容
    using (var outputStream = ContentResolver.OpenOutputStream(newTestFile.Uri))
    using (var streamWriter = new StreamWriter(outputStream))
    {
        streamWriter.WriteLine("这是通过SAF写入的测试内容");
    }
}

这种方式不需要申请传统的WRITE_EXTERNAL_STORAGE权限,完全符合系统的权限规范,兼容性也更强。

3. 额外提示

如果你的应用需要兼容Android 9及以下版本,记得在AndroidManifest.xml中添加对应的存储权限,并且动态申请:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

内容的提问来源于stack exchange,提问作者Large

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 06:54:08