Работа с файловой системой в Kotlin: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в работу с файловой системой в Kotlin

Работа с файловой системой — одна из базовых задач при разработке приложений на Kotlin. Будь то консольное приложение, серверный проект или мобильное приложение под Android, вам почти наверняка потребуется читать, записывать, перемещать или удалять файлы. Kotlin, будучи современным языком, работающим поверх JVM, предоставляет все возможности стандартной библиотеки Java, но при этом добавляет свои удобные расширения и синтаксический сахар.

В этой статье мы подробно разберём, как эффективно работать с файловой системой в Kotlin. Вы узнаете, как создавать и удалять файлы и директории, читать и записывать данные, обходить каталоги и обрабатывать исключения. Все примеры кода будут написаны на чистом Kotlin без использования сторонних библиотек.

Основные классы и подходы

В Kotlin для работы с файловой системой используются два основных API:

  • java.io.File — классический API из Java, который Kotlin расширяет своими функциями-расширениями.
  • java.nio.file.Path и java.nio.file.Files — более современный и функциональный API из Java NIO.

Оба подхода полностью совместимы с Kotlin, но второй (NIO) рекомендуется для новых проектов, так как он предоставляет более богатые возможности и лучшую производительность.

Создание файлов и директорий

Начнём с самого простого — создания файла. В Kotlin это делается очень лаконично:

import java.io.File

fun main() {
    val file = File("example.txt")
    
    // Создание файла (возвращает true, если файл был создан)
    val created = file.createNewFile()
    
    if (created) {
        println("Файл создан: ${file.absolutePath}")
    } else {
        println("Файл уже существует")
    }
    
    // Создание директории
    val dir = File("myDirectory")
    val dirCreated = dir.mkdir() // или mkdirs() для создания вложенных директорий
    
    println("Директория создана: $dirCreated")
}

Обратите внимание на метод mkdirs() — он создаст все недостающие родительские директории, в отличие от mkdir(), который создаёт только последнюю директорию в пути.

Чтение файлов

Kotlin предоставляет элегантные расширения для чтения содержимого файлов. Рассмотрим несколько способов:

import java.io.File

fun readExamples() {
    val file = File("data.txt")
    
    // Чтение всего файла в строку
    val content: String = file.readText()
    println("Содержимое файла:\n$content")
    
    // Чтение построчно в список
    val lines: List<String> = file.readLines()
    lines.forEach { println("Строка: $it") }
    
    // Чтение всех байтов
    val bytes: ByteArray = file.readBytes()
    println("Размер файла: ${bytes.size} байт")
    
    // Чтение с использованием Buffered (для больших файлов)
    file.forEachLine { line ->
        println("Обрабатываем строку: $line")
    }
}

Для больших файлов лучше использовать forEachLine или bufferedReader(), чтобы не загружать весь файл в память.

Запись в файлы

Запись данных в файл также интуитивно понятна:

import java.io.File

fun writeExamples() {
    val file = File("output.txt")
    
    // Запись строки (перезаписывает файл)
    file.writeText("Привет, Kotlin!\nВторая строка")
    
    // Добавление в конец файла
    file.appendText("\nТретья строка (добавлена)")
    
    // Запись списка строк
    val lines = listOf("Строка 1", "Строка 2", "Строка 3")
    file.writeText(lines.joinToString("\n"))
    
    // Запись байтов
    val data = byteArrayOf(72, 101, 108, 108, 111) // "Hello" в ASCII
    file.writeBytes(data)
}

Если вам нужно больше контроля (например, указать кодировку), используйте bufferedWriter():

file.bufferedWriter().use { writer ->
    writer.write("Текст в UTF-8")
    writer.newLine()
    writer.write("Ещё строка")
}

Обход директорий и работа с путями

Одна из частых задач — обход всех файлов в директории. Kotlin делает это очень удобно:

Обход файлов в каталоге

import java.io.File

fun traverseDirectory() {
    val dir = File("myDirectory")
    
    // Получить список файлов (только первого уровня)
    val files: Array<File>? = dir.listFiles()
    files?.forEach { file ->
        println("${if (file.isDirectory) "[DIR]" else "[FILE]"} ${file.name}")
    }
    
    // Рекурсивный обход всех файлов с фильтром
    dir.walk()
        .filter { it.extension == "txt" }
        .forEach { println("Текстовый файл: ${it.name}") }
    
    // Обход в глубину (сверху вниз)
    dir.walk(FileWalkDirection.TOP_DOWN).forEach { println(it.name) }
    
    // Обход в ширину (снизу вверх)
    dir.walk(FileWalkDirection.BOTTOM_UP).forEach { println(it.name) }
}

Метод walk() возвращает последовательность File, которую можно фильтровать, преобразовывать и обрабатывать с помощью стандартных функций Kotlin.

Работа с путями через NIO

API java.nio.file предоставляет больше возможностей, особенно для сложных операций:

import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes

fun nioExamples() {
    val path = Paths.get("myDirectory")
    
    // Создание директории
    Files.createDirectories(path)
    
    // Создание временного файла
    val tempFile = Files.createTempFile("prefix_", ".tmp")
    println("Временный файл: $tempFile")
    
    // Копирование файла
    val source = Paths.get("source.txt")
    val target = Paths.get("backup/source_copy.txt")
    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING)
    
    // Перемещение/переименование
    Files.move(source, Paths.get("new_name.txt"), StandardCopyOption.REPLACE_EXISTING)
    
    // Удаление файла
    Files.deleteIfExists(target)
    
    // Обход дерева файлов с помощью FileVisitor
    Files.walkFileTree(path, object : SimpleFileVisitor<Path>() {
        override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
            println("Файл: ${file.fileName}")
            return FileVisitResult.CONTINUE
        }
        
        override fun preVisit                

Блоги

Рекомендаций по книгам