[英]Android - R/W to removable SD card
我正在創建應用程序,該應用程序應將文件從內部存儲(我的意思是/ storage / emulated / 0 / *)移動到外部可移動存儲(微型SD卡)。 我找到了該SD卡根目錄的路徑,但是無法在其中創建文件夾或移動文件。 我不知道該怎么做才能使其正常工作。 我找到了一個稱為“存儲訪問框架”的東西,但是我不明白如何使用它。 我將感謝您為特定SD卡根路徑獲得讀/寫權限的任何幫助。
先感謝您。
從api 19(KitKat)開始,幾乎不可能直接將SDcard內容作為簡單File
寫入,因為至少對於默認用戶,它們以只讀方式安裝(系統仍然可以對其進行寫入)。
DocumentsProvider
API相當復雜(即使文檔中的示例也很難讀),這就是為什么添加DocumentFile
來模擬File
行為以便於訪問。
假設用戶已被授予讀/寫存儲權限,我們需要獲取SDcard根的文檔URI(在Activity
):
var sdCardUri : Uri? = null
private fun requestSDCardPermissions(){
if(Build.VERSION.SDK_INT < 24){
startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), REQ_PICK_DIRECTORY)
return
}
// find removable device using getStorageVolumes
val sm = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val sdCard = sm.storageVolumes.find { it.isRemovable }
if(sdCard != null){
startActivityForResult(sdCard.createAccessIntent(null), REQ_SD_CARD_ACCESS)
}
}
在使用API 24之前,用戶需要打開文檔選擇器並自己手動選擇SD卡。 這並不理想,但Android團隊忽略了缺少SD卡API的事實。
在較新的版本中, getStorageVolumes()
允許我們通過代碼查找SD卡,並且僅向用戶顯示明確的警告,即將其訪問。 該對話框與“讀/寫存儲”權限不同。
現在要處理獲取的Uri
我們只需要獲取結果的data.data
。 最好將其存儲在共享的首選項中,以防止一遍又一遍地詢問用戶:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if(requestCode == REQ_SD_CARD_ACCESS || requestCode == REQ_PICK_DIRECTORY){
if(resultCode == RESULT_OK) {
if(data == null){
Log.e(TAG, "Error obtaining access")
}else{
sdCardUri = data.data
Log.d("StorageAccess", "obtained access to $sdCardUri")
// optionally store uri in preferences as well here { ... }
}
}else
Toast.makeText(this, "access denied", Toast.LENGTH_SHORT).show()
return
}
super.onActivityResult(requestCode, resultCode, data)
}
我將省去大多數錯誤檢查/文件存在的驗證,但是現在您可以使用這樣獲得的sdCardUri
(將文件“ sample.txt”從內部存儲根復制到SDcard根):
private fun copyToSDCard(){
val sdCardRoot = DocumentFile.fromTreeUri(this, sdCardUri)
val internalFile = File(Environment.getExternalStorageDirectory(), "sample.txt")
// get or create file
val sdCardFile = sdCardRoot.findFile("sample.txt") ?: sdCardRoot.createFile(null, "sample.txt")
val outStream = contentResolver.openOutputStream(sdCardFile.uri)
outStream.write(internalFile.readBytes())
outStream.flush()
outStream.close()
Toast.makeText(this, "copied to SDCard", Toast.LENGTH_SHORT).show()
}
以及其他方式(從SD卡到內部存儲):
private fun copyToInternal(){
val sdCardRoot = DocumentFile.fromTreeUri(this, sdCardUri)
val internalFile = File(Environment.getExternalStorageDirectory(), "sample.txt")
val sdCardFile = sdCardRoot.findFile("sample.txt")
val inStream = contentResolver.openInputStream(sdCardFile.uri)
internalFile.writeBytes(inStream.readBytes())
inStream.close()
Toast.makeText(this, "copied to internal", Toast.LENGTH_SHORT).show()
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.