18-bo‘lim
Fayllar bilan ishlash
Faylga yozish va o'qish, qatorlar bilan ishlash, katta fayllar uchun useLines, papkalar, use bilan resursni yopish va oddiy CSV tahlili.
Ushbu bo‘lim mundarijasi
Dastur to'xtaganda xotiradagi hamma narsa yo'qoladi. Ma'lumotni saqlab qolish uchun uni faylga yozish kerak.
Kotlin da bu Java ga qaraganda ancha qisqa - File sinfiga
kengaytmalar qo'shilgan.
Eng oddiy yozish va o'qish #
import java.io.File
fun main() {
val fayl = File("qaydlar.txt")
fayl.writeText("Birinchi qator\nIkkinchi qator")
println(fayl.readText())
fayl.appendText("\nUchinchi qator")
println("---")
println(fayl.readText())
fayl.delete()
println(fayl.exists())
}
Birinchi qator
Ikkinchi qator
---
Birinchi qator
Ikkinchi qator
Uchinchi qator
false
| Metod | Nima qiladi |
|---|---|
writeText(s) | Faylga yozadi (ustiga yozadi) |
appendText(s) | Oxiriga qo'shadi |
readText() | Butun faylni satr qilib o'qiydi |
exists() | Fayl bormi |
delete() | O'chiradi |
writeText mavjud faylni so'ramasdan ustiga yozadi. Qo'shish
kerak bo'lsa appendText, yoki avval exists() bilan tekshiring.
Bu ayniqsa foydalanuvchi ma'lumoti bilan ishlaganda xavfli.
Qatorlar bilan #
import java.io.File
fun main() {
val fayl = File("talabalar.txt")
val royxat = listOf("Malika", "Husanboy", "Nodira", "Aziza")
fayl.writeText(royxat.joinToString("\n"))
val oqilgan = fayl.readLines()
println("Jami: ${oqilgan.size}")
oqilgan.forEachIndexed { i, ism ->
println("${i + 1}. $ism")
}
println(oqilgan.filter { it.startsWith("A") })
fayl.delete()
}
Jami: 4
1. Malika
2. Husanboy
3. Nodira
4. Aziza
[Aziza]
readLines() ro'yxat qaytaradi - shuning uchun 10-bo'limdagi hamma
funksiya darhol ishlaydi.
Katta fayllar - useLines #
import java.io.File
fun main() {
val fayl = File("sonlar.txt")
fayl.writeText((1..1000).joinToString("\n"))
val jami = fayl.useLines { qatorlar ->
qatorlar.map { it.toInt() }.filter { it % 3 == 0 }.sum()
}
println("3 ga bo'linadiganlar yig'indisi: $jami")
var soni = 0
fayl.forEachLine { soni++ }
println("Qatorlar: $soni")
fayl.delete()
}
3 ga bo'linadiganlar yig'indisi: 166833
Qatorlar: 1000
readText() butun faylni xotiraga yuklaydi. 10 KB uchun bu
normal, 2 GB uchun esa dastur qulaydi.
useLines faylni ketma-ketlik sifatida beradi: qatorlar birma-bir
o'qiladi va xotirada faqat bittasi turadi. Blok tugagach fayl
avtomatik yopiladi.
Qoida: fayl hajmini oldindan bilmasangiz - useLines.
use - resursni avtomatik yopish #
import java.io.File
fun main() {
val fayl = File("hisobot.txt")
fayl.bufferedWriter().use { yozuvchi ->
yozuvchi.write("Sarlavha")
yozuvchi.newLine()
repeat(3) { i ->
yozuvchi.write("Qator ${i + 1}")
yozuvchi.newLine()
}
}
fayl.bufferedReader().use { oquvchi ->
println(oquvchi.readText().trim())
}
fayl.delete()
}
Sarlavha
Qator 1
Qator 2
Qator 3
use { } - blok tugaganda (xato bo'lsa ham) resursni avtomatik
yopadi. Bu Java dagi try-with-resources ning Kotlin shakli.
use yozmasangiz va xato yuz bersa, fayl ochiq qolishi mumkin.
Keyin uni boshqa dastur o'chira ham, o'zgartira ham olmaydi.
use har qanday Closeable bilan ishlaydi - fayl, tarmoq ulanishi,
ma'lumotlar bazasi.
Yo'llar va papkalar #
import java.io.File
fun main() {
val papka = File("sinov_papka")
papka.mkdirs()
println(papka.exists())
File(papka, "a.txt").writeText("A")
File(papka, "b.txt").writeText("B")
val fayllar = papka.listFiles()?.sortedBy { it.name } ?: emptyList()
println("Fayllar: ${fayllar.size}")
fayllar.forEach { println(" ${it.name} (${it.length()} bayt)") }
papka.deleteRecursively()
println(papka.exists())
}
true
Fayllar: 2
a.txt (1 bayt)
b.txt (1 bayt)
false
Diqqat: listFiles() null qaytarishi mumkin (papka bo'lmasa
yoki ruxsat yetmasa), shuning uchun ?: bilan himoyalangan.
Va yana: u tartibni kafolatlamaydi - sortedBy qo'shildi.
Fayl nomining qismlari #
import java.io.File
fun main() {
val fayl = File("hujjatlar/hisobot.pdf")
println(fayl.name)
println(fayl.nameWithoutExtension)
println(fayl.extension)
println(fayl.parent)
println(fayl.path.replace("\\", "/"))
}
hisobot.pdf
hisobot
pdf
hujjatlar
hujjatlar/hisobot.pdf
replace("\", "/") faqat shu darslik uchun - natija har ikkala
tizimda bir xil ko'rinishi kerak edi. O'z kodingizda bu kerak emas.
Oddiy CSV #
import java.io.File
data class Talaba(val ism: String, val ball: Int, val guruh: String)
fun oqi(fayl: File): List<Talaba> =
fayl.readLines()
.drop(1)
.filter { it.isNotBlank() }
.mapNotNull { qator ->
val qismlar = qator.split(",").map { it.trim() }
if (qismlar.size != 3) return@mapNotNull null
val ball = qismlar[1].toIntOrNull() ?: return@mapNotNull null
Talaba(qismlar[0], ball, qismlar[2])
}
fun main() {
val fayl = File("talabalar.csv")
fayl.writeText(
"""
ism,ball,guruh
Malika,88,A
Husanboy,92,B
Nodira,xato,A
Aziza,95,B
""".trimIndent()
)
val talabalar = oqi(fayl)
println("O'qildi: ${talabalar.size} ta")
talabalar.forEach { println(" $it") }
println("O'rtacha: ${talabalar.map { it.ball }.average()}")
fayl.delete()
}
O'qildi: 3 ta
Talaba(ism=Malika, ball=88, guruh=A)
Talaba(ism=Husanboy, ball=92, guruh=B)
Talaba(ism=Aziza, ball=95, guruh=B)
O'rtacha: 91.66666666666667
Buzuq qator (Nodira,xato,A) jimgina tashlab yuborildi - mapNotNull
null qaytargan elementlarni olib tashlaydi.
return@mapNotNull - lambda dan chiqish usuli. Oddiy return butun
funksiyadan chiqarib yuborardi.
Yozib chiqarish #
import java.io.File
data class Mahsulot(val nom: String, val narx: Int)
fun main() {
val ombor = listOf(
Mahsulot("Olma", 12000),
Mahsulot("Anor", 18000),
Mahsulot("Uzum", 22000)
)
val fayl = File("ombor.csv")
fayl.bufferedWriter().use { w ->
w.write("nom,narx")
w.newLine()
ombor.forEach {
w.write("${it.nom},${it.narx}")
w.newLine()
}
}
println(fayl.readText().trim())
fayl.delete()
}
nom,narx
Olma,12000
Anor,18000
Uzum,22000
Xatolarni hisobga olish #
import java.io.File
fun xavfsizOqi(yol: String): String {
val fayl = File(yol)
if (!fayl.exists()) return "Fayl topilmadi: $yol"
return runCatching { fayl.readText() }
.getOrElse { "O'qib bo'lmadi: ${it::class.simpleName}" }
}
fun main() {
val fayl = File("bor.txt")
fayl.writeText("mazmun")
println(xavfsizOqi("bor.txt"))
println(xavfsizOqi("yoq.txt"))
fayl.delete()
}
mazmun
Fayl topilmadi: yoq.txt
Fayl bilan ishlashda hamma narsa noto'g'ri ketishi mumkin: fayl
o'chirilgan, ruxsat yo'q, disk to'lgan. Shuning uchun tekshiruv va
runCatching birga ishlatiladi.
Kotlin da JSON uchun kotlinx.serialization kutubxonasi ishlatiladi:
@Serializable
data class Talaba(val ism: String, val ball: Int)
val json = Json.encodeToString(talaba)
val qayta = Json.decodeFromString<Talaba>(json)
U data class bilan juda yaxshi ishlaydi, lekin loyihaga
qo'shimcha plagin va bog'liqlik talab qiladi - shuning uchun bu
darslikda ishlatilmadi.
Gradle loyihasida kotlin("plugin.serialization") plaginini va
kotlinx-serialization-json bog'liqligini qo'shsangiz, yuqoridagi
kod ishlaydi.
- Matnni faylga yozib, qayta o'qing.
appendTextbilan yangi qator qo'shing.readLines()bilan o'qib,filterqo'llang.useLinesbilan katta faylni qayta ishlang.use { }bilan yozing va uni tushirib qoldirib ko'ring.- Papka yaratib, ichiga ikkita fayl yozing.
listFiles()natijasini saralab chiqaring.- Fayl kengaytmasini
extensionbilan oling. - CSV faylni o'qib,
data classro'yxatiga aylantiring. - Mavjud bo'lmagan faylni o'qishga urinib, xatoni ushlang.
Xulosa #
File("nom").writeText()ustiga yozadi; qo'shish uchunappendText.readLines()ro'yxat beradi - kolleksiya funksiyalari darhol ishlaydi.- Katta fayllar uchun
useLinesyokiforEachLine. use { }resursni xato bo'lsa ham avtomatik yopadi.listFiles()nullqaytarishi mumkin va tartibni kafolatlamaydi.mapNotNull+return@mapNotNull- buzuq qatorlarni tashlab ketishning toza usuli.- Fayl amallarini
exists()tekshiruvi varunCatchingbilan himoyalang.
Keyingi bo'limda korutinlarni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.