我创建的应用程序,这应该从内部存储移动文件(我的意思/存储/模拟/ 0 / *)到外部移动存储(micro SD卡)。 我找到的路径SD卡的根目录,但我无法创建文件夹或文件移动那里。 我不知道怎样做才能使其发挥作用。 我发现一些所谓的存储访问框架,但我不明白,如何使用它。 我感谢所有帮助获得读取特定SD卡的根路径/写权限。
先感谢您。
我创建的应用程序,这应该从内部存储移动文件(我的意思/存储/模拟/ 0 / *)到外部移动存储(micro SD卡)。 我找到的路径SD卡的根目录,但我无法创建文件夹或文件移动那里。 我不知道怎样做才能使其发挥作用。 我发现一些所谓的存储访问框架,但我不明白,如何使用它。 我感谢所有帮助获得读取特定SD卡的根路径/写权限。
先感谢您。
由于API 19(奇巧)这几乎是不可能直接写入到SD卡的内容作为一个简单的File
,因为他们只为默认的用户至少安装为READ(系统还可以写入)。
DocumentsProvider
API是颇为曲折的(即使是在文档样本是很难读),这就是为什么DocumentFile
加入模拟File
的行为更容易获得。
已经授予假设用户读/写存储的权限,我们需要获得SD卡根的文件的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)
}
}
前24 API用户需要打开文件选择器和手动选择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
像这样(复制从内部存储根到SD卡根目录文件“为sample.txt”):
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()
}