【发布时间】:2023-02-16 21:24:54
【问题描述】:
我随机验证了一个在 Samsung Tab S8 设备上写入 ExternalFilesDir 的问题。
我创建了一个写入此路径的测试应用程序:包文件夹/文档/files.txt
为此,我遵循了以下步骤:
我在外部文件目录中创建一个文档文件夹
val documents = File(applicationContext.getExternalFilesDir(null), "documents")
val documentsMkdirResult = documents.mkdirs()
并且这个文件夹是正确创建的,然后
我尝试在文档中创建一个名为“testFolder”的文件夹:
val fileFolder = File(documents, "testFolder")
val fileFolderResult = fileFolder.mkdirs()
我创建了 readme.txt 文件:
val txtFile = File(documents, "readme.txt")
val result = txtFile.createNewFile()
但有时 createNewFile 会因以下异常而失败:
17:20:35 W System.err : java.io.IOException: Permission denied
17:20:35 W System.err : at java.io.UnixFileSystem.createFileExclusively0(Native Method)
17:20:35 W System.err : at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
17:20:35 W System.err : at java.io.File.createNewFile(File.java:1006)
发生此问题时,名为“testFolder”的文件夹均未创建 readme.txt
我在这个设备上的 saucelabs 上测试了这个问题: 三星 Tab S8、S8 ultra 和 S8+。
我没有在我的 Samsung Tab s8 上验证问题
这是完整的测试代码:
class MainActivity : AppCompatActivity() {
private var resultText: TextView? = null
private var resultButton: Button? = null
private var resultAsString = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
resultText = findViewById<TextView>(R.id.resultTest)
resultButton = findViewById<Button>(R.id.resultButton)
resultButton!!.visibility = View.GONE
Thread{
startTest()
}.start()
}
private fun startTest() {
try {
runOnUiThread{
resultAsString += "\ngetExternalFilesDir..."
resultText!!.text = resultAsString
}
val documents = File(applicationContext.getExternalFilesDir(null), "documents")
val documentsMkdirResult = if(!documents.exists()){
documents.mkdirs()
}else{
true
}
val fileFolder = File(documents, "testFolder")
val fileFolderResult = if(!fileFolder.exists()) {
fileFolder.mkdirs()
}else{
true
}
if(documentsMkdirResult) {
val txtFile = File(documents, "readme.txt")
val result = txtFile.createNewFile()
runOnUiThread{
resultAsString += "\nTest performed successfully"
resultText!!.text = resultAsString
}
}else{
runOnUiThread{
resultAsString += "\nDocuments Folder not exists"
resultText!!.text = resultAsString
}
}
} catch (e: Exception) {
runOnUiThread{
resultAsString += "\n ${e.message}"
resultText!!.text = resultAsString
resultButton!!.text = "Error"
resultButton!!.visibility = View.VISIBLE
}
}
}
companion object {
private const val TAG = "MainActivity"
}
}
minsdk 23 目标和编译 sdk 32
getExternalFilesDir从 Build.VERSION_CODES.KITKAT 开始,不需要读取或写入权限返回路径;调用应用程序始终可以访问它。这仅适用于为调用应用程序的包名称生成的路径。要访问属于其他包的路径,需要 Manifest.permission.WRITE_EXTERNAL_STORAGE 和/或 Manifest.permission.READ_EXTERNAL_STORAGE。
【问题讨论】:
-
app that write in this path: packageFolder/documents/file/files.txt对不起,这样的路径不存在。它也不是完整路径。 -
val txtFile = File(documents, "files.txt")不应该是:val txtFile = File(fileFolder, "files.txt")吗? -
如果文件夹尚不存在,您应该只调用 mkdir()。因为如果文件夹已经存在,mkdirs() 将返回 false。
-
请重写您的代码以使用 if (!file.exists()) if ( !file.mkdirs()) return;如果无法强制需要的文件夹,请不要继续。
-
TAG, "getExternalStorageDirectory那不是 getExternalFilesDir() !
标签: android kotlin android-external-storage saucelabs