Android存儲訪問框架SAF:給應用裝上"智能導航儀"
當文件管理遇上"智能管家"
你的手機是個大倉庫,各種文件就是里面的貨物。傳統方式就像給倉庫管理員萬能鑰匙?? - 雖然方便但風險巨大!而SAF就像給管理員配了個智能導航儀??,讓他只能走你指定的路線,既安全又高效。
SAF的三大超能力
1. 安全盾牌 ??? - 告別"全盤通吃",只接觸你允許的文件
2. 版本通吃王 ?? - 從Android 5.0到最新系統全兼容
3. 用戶遙控器 ?? - 文件訪問權完全由你掌控
三大實戰場景解密
場景1:打開文件就像點外賣
fun orderFile() {
// 啟動"文件外賣"界面
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
// 只選可操作文件
addCategory(Intent.CATEGORY_OPENABLE)
// 只要圖片文件
type = "image/*"
}
startActivityForResult(intent, FILE_PICK_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
data?.data?.let { fileUri ->
// 獲取"永久通行證"
contentResolver.takePersistableUriPermission(
fileUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
// 現在可以盡情使用文件啦!
displayImage(fileUri)
}
}
}1. 用戶點擊"選文件"按鈕
2. 彈出系統文件選擇器(像外賣平臺)
3. 選中文件后自動獲得訪問權限
4. 應用立即展示文件內容
場景2:創建新文件就像發微博
fun createPost() {
// 啟動"文件創作"界面
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
type = "text/plain"http:// 文本類型
putExtra(Intent.EXTRA_TITLE, "我的日記.txt") // 默認文件名
}.also { startActivityForResult(it, CREATE_FILE_CODE) }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
data?.data?.let { newFileUri ->
// 把內容"發布"到新文件
contentResolver.openOutputStream(newFileUri)?.use { stream ->
stream.write("今天是個好日子!".toByteArray())
}
// 提示用戶發布成功
showToast("日記保存成功!??")
}
}
}1. 用戶自選保存位置
2. 系統自動處理命名沖突
3. 支持添加文件描述信息
場景3:管理文件夾就像整理書架
fun organizeBookshelf() {
// 請求訪問整個"書架"
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
// 設置初始位置(可選)
if (android.os.Build.VERSION.SDK_INT >= 26) {
putExtra(DocumentsContract.EXTRA_INITIAL_URI,
Uri.parse("content://com.android.externalstorage.documents/root/primary"))
}
}.also { startActivityForResult(it, FOLDER_ACCESS_CODE) }
}
fun scanBookshelf(folderUri: Uri) {
// 掃描"書架"所有文件
val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
folderUri,
DocumentsContract.getTreeDocumentId(folderUri)
)
contentResolver.query(childrenUri, null, null, null, null)?.use { cursor ->
while (cursor.moveToNext()) {
// 獲取文件信息
val fileName = cursor.getString(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME))
val fileType = cursor.getString(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE))
// 根據類型分類處理
when {
fileType.startsWith("image/") -> processImage(fileName)
fileType == "application/pdf" -> processPDF(fileName)
}
}
}
}? 支持遞歸遍歷子文件夾
? 自動獲取文件修改時間
? 精確顯示文件大小
高手進階技巧
SAF vs 傳統方式 終極PK
能力項 | 傳統方式 | SAF智能導航 |
安全指數 | ?? 裸奔風險 | ?? 金庫級防護 |
用戶控制 | ??♂? 用戶不知情 | ?? 用戶全權掌控 |
Android適配 | ?? 版本兼容噩夢 | ?? 全版本通吃 |
長期訪問 | ?? 可能突然失效 | ?? 永久訪問授權 |
大文件傳輸秘籍
fun transferBigFile(uri: Uri) {
// 使用文件描述符提高性能
contentResolver.openFileDescriptor(uri, "r")?.use { pfd ->
// 創建內存映射緩沖區
val length = pfd.statSize
val buffer = ByteBuffer.allocateDirect(length.toInt())
// 高效讀取大文件
FileInputStream(pfd.fileDescriptor).use { stream ->
stream.channel.read(buffer)
}
// 處理文件內容...
processBigFile(buffer)
}
}異常防護盾
try {
// SAF操作包一層異常處理
} catch (e: FileNotFoundException) {
showError("文件神秘消失了!??")
} catch (e: SecurityException) {
showError("訪問權限被收回了!??")
} catch (e: IOException) {
showError("文件傳輸遇到障礙!??")
}智能文件過濾
// 只要音樂和文檔
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(
"audio/*",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
))SAF不僅僅是技術升級,更是用戶體驗的革命!
? 精準定位文件位置
? 自動避開風險區域
? 把控制權真正交還用戶
現在就開始給你的應用裝上這顆"智能芯",讓文件管理變得既安全又輕松!

























