#android #kotlin #directory #storage #mkdir
Вопрос:
Об этом уже спрашивали раньше, но я не могу найти ответ, который хорошо подходит для меня.
У меня есть приложение, в котором при первом запуске мне нужно создать несколько каталогов и файлов в этих каталогах.
То, что я сделал до сих пор, хорошо работает на Android с 5 по 9. К моему удивлению, он не работает на Android 10 , так как getExternalStorageDirectory() устарел.
Это то, что я делаю до сих пор:
if(isFirstRun)
{
Log.i("MyApp","ServerWizardActivity > createNecesaryFoldersFiles > isFirstRun")
val absoluteExternalStorageDirectory = Environment.getExternalStorageDirectory().getAbsolutePath()
val appDirectory = File("${absoluteExternalStorageDirectory}/MyApp/")
val picturesDirectory = File("${absoluteExternalStorageDirectory}/Pictures/")
val fullPath: String? = "${absoluteExternalStorageDirectory}/MyApp/${jsonFileName}"
var dataFile = File(fullPath)
if (!appDirectory .exists())
{
Log.i("MyApp","ServerWizardActivity > createNecesaryFoldersFiles > appDirectory")
appDirectory .mkdir()
}
if (!picturesDirectory.exists())
{
Log.i("MyApp","ServerWizardActivity > createNecesaryFoldersFiles > picturesDirectory")
picturesDirectory.mkdir()
}
if(!dataFile.exists())
{
Log.i("MyApp","ServerWizardActivity > createNecesaryFoldersFiles > dataFile")
dataFile.createNewFile()
}
}
else
{
Log.i("MyApp","ServerWizardActivity > createNecesaryFoldersFiles > isNotFirstRun")
}
Пока все хорошо.
Однако мне нужно создать каталог непосредственно в хранилище устройства, на том же уровне, что и DCIM, Изображения, документы и загрузки, чтобы я мог согласовать его с версией Android 5-9 и версией приложения iOS.
Я попробовал приведенный ниже код для Android 10 , и он работает, но я могу создать каталог только в одном из каталогов в среде (в данном случае каталог изображений). Есть ли какой-нибудь способ обойти это? Я не хочу менять всю структуру приложения из-за этого.
if(isFirstRun)
{
val resolver = contentResolver
val contentValues = ContentValues()
contentValues.put(
MediaStore.MediaColumns.RELATIVE_PATH,
Environment.DIRECTORY_PICTURES "/MyApp"
)
val path = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).toString()
val folder = File(path)
val isCreated = folder.exists()
if (!isCreated)
{
folder.mkdirs()
}
}
О, и до сих пор они есть у меня в файле манифеста Android:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:requestLegacyExternalStorage="true"
</application>
Комментарии:
1. Возможно, вы могли бы использовать
ACTION_OPEN_DOCUMENT_TREE
и позволить пользователю решить, где на устройстве пользователя (или в выбранном пользователем поставщике облачных хранилищ) ваше приложение должно хранить контент пользователя .2. @CommonsWare — Это не мое дело. И поскольку приложение должно работать так же, как версия iOS, мне пришлось бы изменить и эту версию, а это не вариант.
3. Пользователь, находящийся вне вашего приложения, может создать каталог из корневого каталога внешнего хранилища, но у пользователя нет другого способа (кроме как через
ACTION_OPEN_DOCUMENT_TREE
) предоставить вам доступ к этому каталогу. Если ваше приложение будет распространяться через Play Store, вашandroid:requestLegacyExternalStorage="true"
подход не будет работать, начиная с конца этого года, и весьма маловероятно, что Google предоставит вам отказ от использованияMANAGE_EXTERNAL_STORAGE
.4. @CommonsWare Спасибо за информацию. Не уверен, что приложение будет проходить через PlayStore (версия для iOS размещена в доме). Я попытаюсь понять, как я могу изменить структуру, не слишком влияя на функциональность.
Ответ №1:
Попробуйте использовать следующий код, который поможет вам создать тестовый каталог внутри каталога документов.
//Make sure don't forget to ask runtime permission of read/write file
private fun writeFile(fileData: String, fileName: String) {
val dir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
.toString() "/" "test"
)
} else {
File(
Environment.getExternalStorageDirectory()
.toString() "/${Environment.DIRECTORY_DOCUMENTS}/" "test"
)
}
dir.apply {
if (!this.exists()) this.mkdir()
File(this, "$fileName.txt").apply {
if (!this.exists()) this.createNewFile()
FileOutputStream(this).apply {
write(fileData.toByteArray())
close()
}
}
}
}
Комментарии:
1. Спасибо. Я попробую это сделать. Проблема в том, что мне нужен каталог, созданный на уровне выше, на том же уровне, что и DIRECTORY_DOCUMENTS, а не внутри него. Поначалу все приложение было разработано именно так.
2. К сожалению, я продолжаю получать эту ошибку: «java.io.IOException: Нет такого файла или каталога» при запуске приложения на моем телефоне. И по какой-то причине я не могу создать A10 AVDs, чтобы протестировать его, так как я продолжаю запускать BSOD…