MAUI 中读取应用沙箱(LocalFolder)最安全的方式
MAUI 的
FileSystem.AppDataDirectory是默认且唯一推荐的持久化存储位置,它对应各平台的沙箱私有目录(如 iOS 的
Application Support、Android 的
getFilesDir()、Windows 的
AppData\Local\Packages...\LocalState)。这个路径无需额外权限,所有读写都天然受系统保护。 直接用
Path.Combine(FileSystem.AppDataDirectory, "config.json")构造路径,别拼字符串斜杠 写文件前务必先
Directory.CreateDirectory(Path.GetDirectoryName(filePath))读取时用
File.ReadAllTextAsync(filePath),避免阻塞 UI 线程 不要尝试把
AppDataDirectory当成“根目录”去遍历——它不支持
Directory.EnumerateFiles递归扫描(某些平台会抛
UnauthorizedAccessException)
访问用户文档/下载等共享目录需运行时权限 + 平台特异性处理
FileSystem.OpenDocumentPickerAsync()和
FileSystem.SaveDocumentPickerAsync()是跨平台唯一合规方式,适用于让用户主动选择文件。直接硬编码访问
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)在 iOS/macOS 上无效,在 Android 上需要
READ_EXTERNAL_STORAGE(API 33+ 已弃用),在 Windows 上虽能返回路径但可能被 UAC 或 OneDrive 重定向。 Android:必须在
AndroidManifest.xml声明
android:requestLegacyExternalStorage="true"(仅限 targetSdk GetExternalStoragePublicDirectory 返回空 iOS:完全禁止直接访问
Documents文件夹,只能通过
UIDocumentPickerViewController(即 MAUI 封装的
OpenDocumentPickerAsync) Windows:
KnownFolders.DocumentsLibrary需在
Package.appxmanifest中声明
capabilities,且用户必须授予权限(首次调用会弹窗)
读取 Assets 资源文件要用 FileSystem.OpenAppPackageFileAsync
放在
Resources\Raw\下的文件(如
Resources\Raw\default.json)不是普通磁盘文件,不能用
File.ReadAllText直接读。MAUI 把它们打包进应用包体,需通过流式打开: 调用
await FileSystem.OpenAppPackageFileAsync("default.json") 返回 Stream必须用
using var stream = ...确保及时释放,否则后续重复调用可能卡死或返回 null 该方法不支持子目录嵌套(如
"data/config.json"会失败),资源名必须与
Resources\Raw\下的文件名完全一致(区分大小写) 如果是图片或二进制资源,别用
StreamReader,直接
stream.CopyToAsync(destStream)
调试时路径看不见?用 Debugger.Break()
+ 输出日志确认真实路径
FileSystem.AppDataDirectory在不同设备上路径差异极大,模拟器和真机也不同。光靠文档推测容易出错。 在读写前加
Console.WriteLine($"AppData: {FileSystem.AppDataDirectory}");
Android 上可搭配 adb shell run-as your.package.id ls -l files/查看实际内容 iOS 上无法命令行访问,但可在断点处用
NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0]对比验证 Windows 上注意路径中含大段哈希串,不要手动复制粘贴,始终用变量传递
沙箱路径本身不难获取,真正容易翻车的是「以为路径存在就一定能读写」——每个平台对子目录创建、文件锁、编码格式、甚至隐藏文件(如 .DS_Store)的处理都不同。动手前先用最小路径写个空文件再读出来,比查十篇文档更可靠。
