SAF 文件访问与导入路径
为什么全程 SAF
Android 10+ 引入了 Scoped Storage(分区存储),应用不能再直接访问 /sdcard/ 下的任意文件。ZenConverter 从一开始就走 SAF(Storage Access Framework),好处是:
- 不申请
READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE等大范围存储权限; - 用户通过系统文件选择器主动选择要处理的文件,应用只拿到选中文件的访问权限;
- 可以访问云盘(Google Drive、OneDrive)、SMB 网络盘、文件管理器应用等任意实现了 SAF provider 的来源。
四种导入路径
| 入口 | 说明 | 适用场景 |
|---|---|---|
| 文件选择器(ACTION_GET_CONTENT) | 弹出系统文件选择器,选一个或多个文件 | 从任意来源选文件 |
| 系统相册(ACTION_PICK) | 弹出相册选择器,只选图片/视频 | 只选相册里的图片视频 |
| 整个文件夹 | 选一个文件夹,ZenConverter 扫描里面的文件 | 批量转换某个目录下的文件 |
| ACTION_SEND 分享导入 | 从其他应用"分享"过来(微信/浏览器/文件管理器等) | 不用打开 ZenConverter 就能导入 |
v0.2.3 版本做了关键改进:优先用 ACTION_GET_CONTENT 而不是 ACTION_PICK。原因是 ACTION_PICK 只支持有限的文件提供方,ACTION_GET_CONTENT 对云盘、SMB、第三方文件管理器的兼容性更好。
文件描述符 vs 文件路径
ZenConverter 内部不存文件的绝对路径(比如 /storage/emulated/0/DCIM/IMG_0001.jpg),只存 SAF 的 content URI(比如 content://com.android.externalstorage.documents/document/primary:DCIM/IMG_0001.jpg)和对应的 文件描述符(ParcelFileDescriptor)。
转换引擎拿到的是文件描述符(文件句柄),不是文件路径。这样好处是:
- 云盘文件不需要先下载到本地临时目录再处理;
- 避免了"文件被移动/重命名后路径失效"的问题;
- 更安全——应用不能枚举目录里的其他文件。
混合文件的独立路由
选多个文件时可以混合不同类型(比如同时选 JPG、MP4、DOCX)。ZenConverter 会自动识别每个文件的 MIME 类型,给每个文件独立路由到对应的转换引擎:
- JPG → 图片互转管线;
- MP4 → 视频互转管线;
- DOCX → Office 转换管线。
混合文件不需要你手动分批次导入——一次选完、各自配置、各自跑。
批量同类文件的统一配置
如果选的是同类文件(比如全是 MP4),ZenConverter 会默认给它们统一一套配置(输出格式、压缩预设、裁剪范围等)。你可以批量改所有文件的配置,也可以单独改某一个。
已知边界
- 某些厂商的 SAF 实现有 bug:少数定制 Android(部分国产 ROM)的 SAF provider 实现不完整,可能导致云盘文件或某些第三方文件管理器里的文件无法选中;
- 文件夹扫描是一层:选文件夹时 ZenConverter 只扫描一层,不会递归扫描子文件夹;
- 临时文件会被清理:某些 SAF provider(比如云盘)返回的文件描述符是临时的,云盘同步状态变化后可能失效——转换任务需要在有效时间内完成。
使用场景
| 场景 | 推荐导入路径 |
|---|---|
| 从微信里收到一个 DOCX 想转 PDF | 微信里打开文件 → 分享 → ZenConverter |
| 批量把相册里 20 张 HEIC 转 JPG | ZenConverter → 相册选择 → 多选 |
| 从 OneDrive 选一个 PDF 想压缩 | ZenConverter → 文件选择器 → OneDrive |
| 把整个文件夹的 MP3 都转 OPUS | ZenConverter → 文件夹选择 |
相关页面
- 前台服务与任务队列 —— 导入后进入任务队列
- 视频格式互转原理 —— 导入的 MP4 最终走哪条管线
- 本地优先就是隐私优先 —— SAF 不申请大权限的好处
