Введение
Работа с файловой системой — одна из базовых задач в любом языке программирования. В Kotlin, благодаря его лаконичному синтаксису и мощным расширениям стандартной библиотеки Java, выполнение операций с файлами и директориями становится простым и интуитивно понятным.
В этой статье мы на практике разберем основные операции: создание, чтение, запись, копирование, перемещение и удаление файлов и папок. Все примеры написаны на Kotlin и готовы к использованию в ваших проектах. Материал будет полезен как новичкам, так и опытным разработчикам, которые хотят освежить знания или найти оптимальные решения для повседневных задач.
Основные классы и импорты
Для работы с файловой системой в Kotlin используются классы из пакета java.io (например, File) и java.nio.file (например, Path, Files). Современные рекомендации отдают предпочтение java.nio.file, так как этот API более производительный и удобный.
Для всех примеров нам понадобятся следующие импорты:
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.nio.file.StandardOpenOption
Создание файла и директории
Начнем с самого простого — создания нового файла и папки.
// Создание директории
val dir = File("my_directory")
if (!dir.exists()) {
dir.mkdirs() // mkdirs() создает все недостающие родительские директории
println("Директория создана: ${dir.absolutePath}")
}
// Создание файла
val file = File(dir, "example.txt")
if (!file.exists()) {
file.createNewFile()
println("Файл создан: ${file.absolutePath}")
}
Обратите внимание: mkdirs() создает всю цепочку директорий, если ее нет. mkdir() создает только последнюю директорию и вернет false, если родительская папка отсутствует.
Чтение и запись файлов
Это наиболее частые операции. Kotlin предлагает несколько элегантных способов для работы с содержимым файлов.
Запись в файл
val path = Paths.get("my_directory/write_example.txt")
// Строка для записи
val content = "Привет, мир! Это строка записана в файл.\nВторая строка."
// Простая запись строки (перезаписывает файл)
Files.writeString(path, content)
// Запись списка строк
val lines = listOf("Строка 1", "Строка 2", "Строка 3")
Files.write(path, lines)
// Дозапись в конец файла
val additionalContent = "\nДополнительная строка."
Files.writeString(path, additionalContent, StandardOpenOption.APPEND)
Метод Files.writeString() появился в Java 11 и доступен в Kotlin/JVM. Если вам нужна поддержка более старых версий, используйте Files.write() с указанием кодировки.
Чтение из файла
val path = Paths.get("my_directory/write_example.txt")
// Чтение всего содержимого в строку
val fullContent = Files.readString(path)
println("Содержимое файла:\n$fullContent")
// Чтение в список строк
val allLines: List<String> = Files.readAllLines(path)
allLines.forEachIndexed { index, line ->
println("Строка ${index + 1}: $line")
}
// Чтение с использованием Stream (для больших файлов)
Files.lines(path).use { stream ->
stream.forEach { line ->
println("Обрабатываю строку: $line")
}
}
Конструкция .use { ... } гарантирует закрытие потока после обработки, что особенно важно при работе с большими файлами.
Копирование, перемещение и переименование
Эти операции также реализуются через java.nio.file.Files.
Копирование файла
val source = Paths.get("my_directory/example.txt")
val destination = Paths.get("my_directory/backup/example_copy.txt")
// Создаем целевую директорию, если ее нет
Files.createDirectories(destination.parent)
// Копирование с заменой существующего файла
Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING)
println("Файл скопирован в: $destination")
Флаг StandardCopyOption.REPLACE_EXISTING указывает, что если файл назначения уже существует, его нужно перезаписать. Без этого флага операция вызовет исключение.
Перемещение и переименование
Перемещение и переименование в Java NIO — это одна и та же операция Files.move().
val original = Paths.get("my_directory/example.txt")
val renamed = Paths.get("my_directory/renamed_example.txt")
// Переименование (перемещение в той же директории)
Files.move(original, renamed, StandardCopyOption.REPLACE_EXISTING)
println("Файл переименован в: $renamed")
// Перемещение в другую директорию
val moved = Paths.get("my_directory/backup/renamed_example.txt")
Files.createDirectories(moved.parent)
Files.move(renamed, moved, StandardCopyOption.REPLACE_EXISTING)
println("Файл перемещен в: $moved")
Удаление файлов и директорий
Удаление — простая, но важная операция. Будьте осторожны: удаленные данные невозможно восстановить стандартными средствами.
val fileToDelete = Paths.get("my_directory/backup/renamed_example.txt")
val dirToDelete = Paths.get("my_directory/backup")
// Удаление одного файла
if (Files.deleteIfExists(fileToDelete)) {
println("Файл удален: $fileToDelete")
} else {
println("Файл не найден: $fileToDelete")
}
// Удаление пустой директории
if (Files.deleteIfExists(dirToDelete)) {
println("Директория удалена: $dirToDelete")
}
Метод deleteIfExists() безопаснее, чем delete(), так как не выбрасывает исключение, если файл отсутствует. Для удаления непустой директории потребуется рекурсивный обход:
fun deleteRecursively(dir: Path) {
if (Files.isDirectory(dir)) {
Files.list(dir).use { stream ->
stream.forEach { entry ->
deleteRecursively(entry)
}
}
}
Files.deleteIfExists(dir)
}
// Использование
val nonEmptyDir = Paths.get("my_directory")
deleteRecursively(nonEmptyDir)