Быстрое руководство по работе с assets в Android
Коротко: читайте файлы из assets через AssetManager (context.assets) и копируйте их потоками в внутреннюю (context.filesDir или context.getDatabasePath) или внешнюю память (getExternalFilesDir / MediaStore) с учётом Scoped Storage и прав доступа.
Что такое assets и когда их использовать
Папка assets хранит "сырые" файлы (JSON, шрифты, SQLite, изображения и т.д.), сохраняет структуру подпапок и доступна только через AssetManager. Используйте assets для предустановленных небольших данных (конфиги, словари, шрифты). Большие файлы лучше грузить динамически или хранить в res/raw.
Не помещайте в assets очень большие файлы (рекомендно <1 МБ в APK). Для больших бинарных файлов — используйте res/raw, загрузку по сети или app‑specific external storage.
Чтение файлов из assets (Kotlin и Java)
Используйте context.assets.open(name) и читайте поток. Для текстовых файлов — bufferedReader.readText(), для бинарных — работайте с байтами/потоком.
Kotlin — текст:
fun readAssetText(context: Context, name: String): String? =
try {
context.assets.open(name).bufferedReader().use { it.readText() }
} catch (e: IOException) {
e.printStackTrace(); null
}
Java — текст:
public String readAssetText(Context ctx, String name) {
try (InputStream in = ctx.getAssets().open(name);
BufferedReader r = new BufferedReader(new InputStreamReader(in))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = r.readLine()) != null) sb.append(line).append("\n");
return sb.toString();
} catch (IOException e) { e.printStackTrace(); return null; }
}
Для чтения бинарного файла:
context.assets.open("image.png").use { input ->
val bytes = input.readBytes() // избегайте для очень больших файлов
}
Копирование из assets в память устройства
Assets — только для чтения в APK. Копируйте при первом запуске или по требованию в нужную папку.
Копирование во внутреннюю память (рекомендуется — приватно для приложения):
fun copyToInternal(context: Context, assetName: String, destName: String): File? {
val dest = File(context.filesDir, destName)
return try {
context.assets.open(assetName).use { input ->
dest.outputStream().use { output -> input.copyTo(output) }
}
dest
} catch (e: IOException) { e.printStackTrace(); null }
}
Для SQLite копируйте в context.getDatabasePath("mydb.db") и затем открывайте БД — Android применит WAL при необходимости.
Копирование во внешнюю app‑specific директорию (без разрешений):
val dir = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
val dest = File(dir, "myfile.dat")
if (!dest.exists()) {
context.assets.open("asset.dat").use { input -> dest.outputStream().use { input.copyTo(it) } }
}
Для публичных директорий на Android 10+ используйте MediaStore или запросы разрешений/SAF; WRITE_EXTERNAL_STORAGE устаревает и на новых версиях требует осторожности.
Не предполагается, что assets-файлы можно изменять на месте. Также имена файлов в assets чувствительны к регистру.
Работа с подпапками, перечисление и большие файлы
- Открытие в подпапке: assets.open("folder/file.json").
- Получение списка: context.assets.list("folder") — возвращает массив имён.
- Для больших файлов читайте и копируйте потоками (буфер ~8KB), не загружайте весь файл в память.
Частые ошибки
- FileNotFoundException — неверный путь или регистр имени.
- OutOfMemoryError — чтение больших файлов через readBytes(); используйте по‑частям.
- Проблемы с внешней памятью — не учтён Scoped Storage и отсутствуют нужные разрешения.
FAQ
- Нужно ли запрашивать разрешения для getExternalFilesDir()? — Нет, это app‑specific и разрешений не требует.
- Как проверить целостность скопированного файла? — Считайте SHA-256 хеш и сравните с эталоном.
- Как часто копировать данные из assets? — Лениво: при первом запуске или при обновлении версии/контента.
Лучшие практики: копируйте лениво, проверяйте наличие и хеш, тестируйте на реальных устройствах с разными версиями Android и поведением SD-карты.