USB 与移动硬盘备份
USB 外接盘在产品里是一等备份目标,不是「高级用户隐藏开关」。存储引擎的 provider 为 usb。桌面和 iOS 默认 path 模式,Android 必须 bridge,因为 OTG 只有 content://,POSIX 打不开。
iPhone 实际怎么选盘
iOS 没有 FileManager.mountedVolumeURLs(非 macOS 一律空)。所以应用不会弹出「发现 SanDisk」。流程是:
- 插入盘,系统「文件」里能看见它。
- 打开 Azalea → 备份存储 → 新建 USB 配置。
- 选目录。应用保存 security-scoped bookmark,不是记住一个随便的路径字符串。
- 之后每次
withAccess包住整段引擎操作。书签在作用域外再用,会变成 Rust 里难读的权限错误。
2026 年 2 月用 iPhone 15 + SanDisk Extreme 1TB 测过:第一次选目录后锁屏,再开应用提示盘未就绪,点刷新才 isAvailable()。这不是 bug 文案,是 iOS 没有插拔通知。
Android 为什么必须 SAF
OpenDocumentTree 选树,然后 takePersistableUriPermission。不 take,重启授权就没了。SafFileBridge 不用 DocumentFile.findFile(每层 O(n),几万张照片会卡死),优先拼 document id。
拔盘返回 DeviceDetached,不是普通 IO 失败。空间不足是 OutOfSpace。应用层应暂停等重插,而不是把这一项标红后继续扫。
盘上有什么
<root>/.album/manifest.jsonl 追加写。首行版本头,后面是逻辑 key、物理路径、字节、MD5、墓碑。换一台手机认领同一目录,靠这份清单把转义过的文件名还原。.album/ 不会出现在 list 结果里。
exFAT 没有 xattr。如果仍按云盘那样把 MD5 塞进扩展属性,每次 USB 上传都会 ENOTSUP。所以校验值进 manifest,不进文件系统附加属性。
不该预期的事
- 没有
presign_put。 - 不要格式化成 APFS 再给 Android 写。
- 两块盘都叫 Backup 时,用
volumeIdentity()的 UUID 区分,不要靠文件夹名。