簡體   English   中英

Android-讀/寫到可移動SD卡

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM