Как прочитать текстовый файл из ресурсов в Kotlin?
Чтение текстового файла из ресурсов в Kotlin: лучшие практики
Проблема, с которой вы столкнулись, типична для новичков, переходящих с Java на Kotlin. В Kotlin есть несколько элегантных способов чтения файлов из ресурсов, которые короче и безопаснее Java-аналогов. Главное — правильно получить ClassLoader и использовать Kotlin-расширения для работы с потоками.
Способ 1: Чтение через ClassLoader (универсальный)
Этот метод работает в любом контексте: из класса, объекта или top-level функции. Используем object::class.java.classLoader для получения ClassLoader, а затем getResourceAsStream().
import java.io.BufferedReader
import java.io.InputStreamReader
// Пример из объекта
object FileReaderUtil {
fun readFromResources(fileName: String): String {
val inputStream = this::class.java.classLoader.getResourceAsStream(fileName)
?: throw IllegalArgumentException("Файл $fileName не найден в ресурсах")
return BufferedReader(InputStreamReader(inputStream)).use { it.readText() }
}
}
// Пример из top-level функции
fun readResourceFile(fileName: String): String {
val inputStream = object {}::class.java.classLoader.getResourceAsStream(fileName)
?: throw IllegalArgumentException("Файл $fileName не найден")
return inputStream.bufferedReader().use { it.readText() }
}
// Использование
fun main() {
println(FileReaderUtil.readFromResources("data.txt"))
println(readResourceFile("data.txt"))
}
Способ 2: Чтение с помощью Java Class (если есть экземпляр класса)
Если вы находитесь внутри класса (не объекта), можно использовать this::class.java:
class MyClass {
fun readFile(): String {
val inputStream = this::class.java.getResourceAsStream("/data.txt")
?: throw IllegalStateException("Файл не найден")
return inputStream.bufferedReader().use { it.readText() }
}
}
Важно: при использовании getResourceAsStream() от Class (не ClassLoader) путь должен начинаться с / для указания корня classpath.
Способ 3: Использование Kotlin-расширения для File (альтернатива)
Если вы хотите работать с файлом как с объектом java.io.File, можно сначала получить URL ресурса:
import java.io.File
fun readResourceAsFile(fileName: String): String {
val resource = object {}::class.java.classLoader.getResource(fileName)
?: throw IllegalArgumentException("Файл $fileName не найден")
return File(resource.toURI()).readText()
}
Способ 4: Чтение построчно (для больших файлов)
Для больших файлов лучше читать построчно, чтобы не загружать всё в память:
fun processLines(fileName: String) {
val inputStream = object {}::class.java.classLoader.getResourceAsStream(fileName)
?: throw IllegalArgumentException("Файл не найден")
inputStream.bufferedReader().use { reader ->
reader.forEachLine { line ->
println("Строка: $line")
}
}
}
Ключевые моменты:
- Всегда используйте
use { }для автоматического закрытия ресурсов (эквивалент try-with-resources в Java). - Проверяйте
nullотgetResourceAsStream()— если файл отсутствует, вернётсяnull. - Файл должен лежать в
src/main/resources/(для Gradle/Maven) и указываться без пути, только имя, если он в корне. - Используйте
object {}::class.java.classLoaderкак самый надёжный способ получить ClassLoader без привязки к конкретному классу.
Рекомендую использовать первый способ (через ClassLoader) — он наиболее универсальный и работает в любом контексте Kotlin-кода.
<<Альтернативный подход: использование библиотеки kotlinx-io
Если вы используете современные версии Kotlin (1.8+) и хотите более функциональный стиль, можно воспользоваться экспериментальной библиотекой kotlinx-io. Она предоставляет удобные расширения для работы с ресурсами.
// build.gradle.kts
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.3.0")
}
// Чтение файла
import kotlinx.io.Source
import kotlinx.io.readString
import kotlinx.io.use
fun readResourceKotlinx(fileName: String): String {
val inputStream = object {}::class.java.classLoader.getResourceAsStream(fileName)
?: throw IllegalArgumentException("Файл $fileName не найден")
return inputStream.source().use { it.readString() }
}
Дополнительный совет: работа с путями
Если файл лежит в подпапке ресурсов, например src/main/resources/config/settings.txt, указывайте путь относительно корня classpath:
val content = readResourceFile("config/settings.txt")
Также можно использовать Path из Java NIO для более гибкой работы:
import java.nio.file.Paths
import java.nio.file.Files
fun readWithNio(fileName: String): String {
val resource = object {}::class.java.classLoader.getResource(fileName)
?: throw IllegalArgumentException("Файл не найден")
return Files.readString(Paths.get(resource.toURI()))
}
Этот метод удобен, если вы уже используете NIO в проекте. Однако помните, что Files.readString() появился только в Java 11, поэтому для старых версий Java используйте readAllBytes() + String-конструктор.
Ответов пока нет.
Войдите чтобы оставить ответ