CodeGym /Các khóa học /Kotlin SELF /Doc van ban: readText, readLines, forEachLine

Doc van ban: readText, readLines, forEachLine

Kotlin SELF
Mức độ, Bài học
Có sẵn

1. Gioi thieu

Khi noi “doc tep”, nguoi moi thuong hinh dung ra dieu gi do kieu: “chuong trinh mo tep nhu Notepad va thay cac ky tu”. Thuc te, chuong trinh luon lam cong viec “chan hon” (va trung thuc hon): no lay tep va bien noi dung thanh du lieu ben trong ung dung cua ban — thuong nhat la String hoac List<String>.

Voi tep van ban trong Kotlin/JVM, diem tien la thu vien chuan va File cung cap san cac phuong thuc “dung ngay”, va ta co the chon kieu doc phu hop voi bai toan: doc toan bo, doc theo dong vao bo nho, hoac xu ly tung dong gan nhu khong ton bo nho.

Can “dong dinh” mot y: khi chon cach doc, ban dang chon hinh thuc du lieu. Va hinh thuc du lieu anh huong manh den viec viet code ve sau de hay kho, va may tinh “dau” den dau (bo nho va thoi gian).

Chon phuong phap doc nhu the nao

Lua chon giua readText, readLines, forEachLine khong phai la cau hoi “phuong thuc nao dung”, ma la “minh can hinh thuc du lieu nao cho buoc tiep theo” va “tep lon co nao”.

De khoi phai “doan” moi lan, nen co san so sanh ngay truoc mat.

Bang lua chon

Phuong thuc Tra ve gi Bo nho Khi nao tien “Du vi code” thuong gap sau do
readText()
String
doc toan bo mot lan tep la “mot khoi y nghia”: mau (template), doan van ngan, cau hinh lam viec voi chuoi: trim, split, replace, tim kiem chuoi con
readLines()
List<String>
doc toan bo mot lan tep co cau truc theo dong, va ban muon dung cac phep toan tren collection map/filter/count/groupBy, sap xep, phan tich dong
forEachLine {}
khong tra ve truc tiep (ban tu tich luy ket qua) tung dong tep lon hoac co the tinh ket qua “tai cho” (on the fly) bo dem, tim kiem, max/min, tich luy vao MutableList

Co mot diem “tam ly” quan trong: readText() va readLines() dua cho ban ket qua san ngay, con forEachLine buoc ban phai nghi “minh se tich luy cau tra loi nhu the nao”. Dieu nay la binh thuong: xu ly tung dong gan nhu luc nao cung “thuat toan” hon mot chut.

Luu do lua chon

Doi khi de nho mot “tuyen duong” nho hon la bang:

flowchart TD
    A[Can doc van ban tu tep] --> B{Can toan bo tep nhu mot chuoi duy nhat?}
    B -->|Co| C["readText()"]
    B -->|Khong| D{Can co danh sach cac dong trong bo nho?}
    D -->|Co| E["readLines()"]
    D -->|Khong, co the xu ly ngay| F["forEachLine { ... }"]

Neu ban bat gap y nghi “minh khong tien voi forEachLine, minh muon danh sach” — do la tin hieu trung thuc rang co the ban thuc su can readLines(). Chi can nho cai gia: danh sach = bo nho.

Mot tinh tiet ve hieu nang xuat (output)

Doi khi doc tep la de in nhieu dong ra console. Va luc do co cai bay kinh dien: “minh se println trong vong lap cho moi dong”. Ve mat ky thuat thi dung, nhung neu luong xuat lon co the rat cham. Trong cong dong Kotlin, nguoi ta hay khuyen nen ghep output lai va in mot lan bang println thong qua joinToString("\n") khi co nhieu dong.

Hom nay ta khong bien bai giang thanh cuoc dua toi uu, nhung thoi quen “khong in ca trieu println khi khong can” ban co the bat dau ren ngay tu bay gio.

2. readText() — khi can toan bo tep

Doi khi tep chi la “mot mon”: mau thu, file cau hinh nho, bao cao da luu, van ban ghi chu. Trong nhung truong hop nay, tien nhat la lay no thanh mot chuoi. De lam viec do, File co phuong thuc readText().

Sau readText() ban co String, va ban co the lam moi thu voi chuoi ma ban da quen: length, trim(), split(), replace(), tim chuoi con, tao bao cao bang StringBuilder, va con nua.

Vi du toi thieu readText()

Dau tien la vi du nho nhat de cam nhan co che:

import java.io.File

fun main() {
    val text: String = File("data/input.txt").readText()
    println("chars=${text.length}") // chars=...
}

Neu tep nho, cach nay gan nhu luon “de cho nao”: mot bien, mot kieu, va tiep theo la lam viec voi chuoi.

Vi du: doc → chuan hoa → su dung

Thuong thi van ban doc tu tep can “don dep” truoc: bo khoang trang thua o dau/cuoi, kiem tra xem co rong khong.

import java.io.File

fun main() {
    val raw = File("data/title.txt").readText()
    val title = raw.trim()

    println("title='$title'") // title='...'
}

Luu y: trim() o day khong phai “trang diem”, ma la cach phong ve thuc su truoc nhung bat ngo kieu “cuoi tep tinh co them ky tu xuong dong”.

Khi nao readText() la y tuong te

readText() doc toan bo tep vao bo nho nhu mot chuoi. Neu tep lon (vi du log hang tram MB), ban se ton bo nho cho mot String khong lo, va sau do ton them thoi gian cho cac thao tac tren chuoi do. Luc nay nen nghi toi xu ly tung dong.

Mot meo don gian: neu ban co the mo tep bang Notepad va Notepad khong “triet ly nhan sinh” — thi readText() thuong on. Neu Notepad treo va ban kip uong het tach tra — thi dung lam.

3. readLines() — khi can danh sach cac dong

Tinh huong pho bien tiep theo: tep la tap hop cac dong, va moi dong co y nghia. Vi du: danh sach mua sam, danh sach lenh, danh sach ghi chu, danh sach chi tieu. Trong nhung bai toan nay, tien nhat la nhan ngay List<String>, noi moi phan tu la mot dong rieng cua tep. De lam viec do co readLines().

readLines() hay o cho no bien tep thanh mot collection quen thuoc, va voi collection thi ta lam duoc nhieu thu: map, filter, count, firstOrNull, sortedBy, gom nhom, va con nua.

Vi du toi thieu readLines()

import java.io.File

fun main() {
    val lines: List<String> = File("data/input.txt").readLines()
    println("lines=${lines.size}") // lines=...
}

Bay gio ban khong con “mot chuoi mo ho co nhieu dau xuong dong”, ma la cac phan tu ro rang trong danh sach. Dieu nay thuong giup code don gian va de doc hon.

Vi du: tim dong khong rong dau tien

Kich ban rat thuong gap: tep co the co dong trong, va dong “co ich” dau tien lai quan trong.

import java.io.File

fun main() {
    val firstNonBlank = File("data/input.txt")
        .readLines()
        .firstOrNull { it.isNotBlank() }

    println(firstNonBlank) // ví dụ: Hello
}

O day co mot thoi quen quan trong: dung firstOrNull, khong dung first. Vi tep co the rong, va khi do first() se “to chuc bua tiec exception” cho ban.

Vi du: doc chi tieu tu tep van ban

Gia su den thoi diem nay trong khoa hoc, ta da co model chi tieu (no xuat hien khi ta chuyen sang class va data class). Tam thoi ta khong ban ve “dinh dang ly tuong”, ma lay dinh dang dong don gian:

amount|category|comment

Vi du:

350|food|coffee
1200|transport|metro card

Khi do, doc vao bo nho bang readLines() rat tu nhien: ta muon lay danh sach cac dong, roi parse moi dong thanh object.

import java.io.File

data class Expense(val amount: Int, val category: String, val comment: String)

fun parseExpenseOrNull(line: String): Expense? {
    val parts = line.split("|")
    val amount = parts.getOrNull(0)?.toIntOrNull() ?: return null
    val category = parts.getOrNull(1)?.trim().orEmpty()
    val comment = parts.getOrNull(2)?.trim().orEmpty()
    return Expense(amount, category, comment)
}

Bay gio doc tep va bien cac dong thanh chi tieu:

import java.io.File

fun main() {
    val lines = File("data/expenses.txt").readLines()
    val expenses = lines.mapNotNull { parseExpenseOrNull(it) }

    println("loaded=${expenses.size}") // loaded=...
}

Tai sao o day tien nhat la readLines()? Vi ta muon collection va muon ap dung “phong cach collection” (mapNotNull) thay vi tu viet vong lap va dung bien tam.

Gioi han cua readLines()

Giong nhu readText(), readLines() doc tep toan bo, chi khac la khong gom vao mot chuoi ma vao danh sach dong. Nghia la ve bo nho van la “nap het mot lan”. Voi tep nho va vua — rat on. Voi tep rat lon — nen chuyen sang xu ly tung dong.

4. forEachLine { ... } — xu ly tung dong

Doi khi ta khong can luu toan bo tep. Ta chi can duyet qua va dem, tim, loc, nhung khong tao danh sach dong khong lo. De lam viec do, File co phuong thuc doc tung dong forEachLine { line -> ... }. Y tuong rat don gian: Kotlin doc tep theo tung dong va dua moi dong vao lambda cua ban.

Cach tiep can nay thuong dung trong cac bai toan giong xu ly log hoac dau vao lon. Trong tai lieu Kotlin, no duoc nhac den nhu mot cong cu tien cho viec doc tep theo tung dong.

Vi du toi thieu forEachLine

import java.io.File

fun main() {
    var nonBlank = 0

    File("data/input.txt").forEachLine { line ->
        if (line.isNotBlank()) nonBlank++
    }

    println("nonBlankLines=$nonBlank") // nonBlankLines=...
}

Hay de y: ta khong tao List<String>. Ta chi duyet tep va dem.

Vi du: tim so tien chi tieu lon nhat ma khong luu danh sach dong

Neu tep chi tieu co the lon, va ta can vi du gia tri lon nhat cua amount, thi forEachLine rat phu hop:

import java.io.File

fun main() {
    var maxAmount = 0

    File("data/expenses.txt").forEachLine { line ->
        val expense = parseExpenseOrNull(line) ?: return@forEachLine
        if (expense.amount > maxAmount) maxAmount = expense.amount
    }

    println("maxAmount=$maxAmount") // maxAmount=...
}

O day xuat hien return@forEachLine. Day khong phai “return khoi main”, ma la “bo qua dong hien tai”. Ta lam vay neu dong bi loi hoac rong.

Vi sao forEachLine thuong an toan hon ve bo nho

forEachLine cho phep lam viec voi tep nhu “bang chuyen”: dong den → ban xu ly → di tiep. Bo nho khong bi phong to vi danh sach dong. Dieu nay dac biet de chiu khi ban khong biet truoc tep lon co nao (cuoc doi hay tang “bat ngo”).

5. Lap “bo khung” nho: doc tep va chuan bi du lieu cho ung dung

Gio ta se lam mot “khung xuong” doc du lieu gon gang cho ung dung console (tam hieu la tracker chi tieu), nhung theo cach van giu don gian va khong lan sang chu de bai giang sau (ghi) hay nhung ngay sau (I/O tin cay).

Y chinh: ta muon mot ham nhan File va tra ve danh sach chi tieu hop le. Het. Khong “ma thuat”.

Ham doc bang readLines()

import java.io.File

fun loadExpenses(file: File): List<Expense> {
    if (!file.exists() || !file.isFile) return emptyList()

    return file.readLines()
        .mapNotNull { line -> parseExpenseOrNull(line.trim()) }
}

Doc gan nhu van ban tu nhien: “neu khong co tep — tra ve rong; neu co — doc dong va parse”.

Phuong an khac voi forEachLine

import java.io.File

fun loadExpensesStreaming(file: File): List<Expense> {
    if (!file.exists() || !file.isFile) return emptyList()

    val result = mutableListOf<Expense>()
    file.forEachLine { line ->
        val e = parseExpenseOrNull(line.trim()) ?: return@forEachLine
        result.add(e)
    }
    return result
}

Dung, code nhieu hon mot chut. Doi lai, no khong can giu List<String> cho tat ca dong. Ta chi tich luy nhung ban ghi “tot”.

6. Cac loi thuong gap khi doc van ban tu tep

Loi 1: chon readText() “theo thoi quen”, roi ngac nhien vi chuong trinh an bo nho.
readText() la mot phuong thuc rat tot, nhung no dung nghia den tung chu: “doc TAT CA”. Neu tep bat ngo lon, ban se nhan duoc mot String khong lo, va tiep theo la cac thao tac nang ne tren no. Trong truong hop nay, hay chuyen sang readLines() hoac forEachLine() va “nghi theo dong”.

Loi 2: nham lan giua “dong trong tep” va “mot chuoi String duy nhat”.
Sau readText() ban chi co mot chuoi lon, ben trong chua "\n". Nguoi moi doi khi ky vong “tep nhieu dong thi bien cung se co gi do theo dong”. Khong co. Neu ban can lam viec voi tung dong, nhanh (va ro rang) hon la dung readLines() ngay tu dau.

Loi 3: khong chuan hoa dong truoc khi parse.
Ngay ca tep “sach” cung thuong co khoang trang thua o cuoi dong, dong trong, ky tu xuong dong du. Neu ban lam split("|") ngay lap tuc ma khong trim() va khong kiem tra isBlank(), ban se gap bug kho hieu kieu “hom qua chay duoc, hom nay khong”. Phong ve toi thieu la line.trim() va dung toIntOrNull() can than.

Loi 4: quen rang tep co the khong ton tai, va duong dan co the tro vao thu muc.
Neu ban goi File("...").readLines() ngay lap tuc, ma tep khong thay, chuong trinh se bi loi exception. Ta da biet cac kiem tra co ban exists() va isFile — va day chinh la truong hop chung thuc su giup ban giam cang thang. Dac biet trong cac du an hoc tap, noi thu muc va tep thuong xuyen thay doi vi tri.

Loi 5: co gang “return gia tri” tu forEachLine bang return thong thuong.
Ben trong lambda cua forEachLine, return thong thuong co the hoat dong khac voi ky vong (do quy tac return trong lambda). Neu ban muon bo qua dong — hay dung return@forEachLine. Neu ban muon tich luy ket qua — tao bien ben ngoai va cap nhat no ben trong lambda.

Loi 6: tron doc tep va business logic phuc tap trong mot khoi lon.
Khi ben trong forEachLine hoac sau readLines() lap tuc bat dau mot “tam vai” gom nhieu dieu kien, dem/toan, va dinh dang bao cao, code se kho doc va kho debug. Binh tinh hon neu giu phong cach: “doc → nhan cau truc du lieu → xu ly tiep”, ke ca khi cau truc du lieu hien tai van con don gian.

1
Nhiệm vụ
Kotlin SELF, mức độ, bài học
Đã khóa
Ghi chú của nhà phân tích
Ghi chú của nhà phân tích
1
Nhiệm vụ
Kotlin SELF, mức độ, bài học
Đã khóa
Danh sách sạch
Danh sách sạch
1
Nhiệm vụ
Kotlin SELF, mức độ, bài học
Đã khóa
Nhiệt độ cảm biến
Nhiệt độ cảm biến
1
Nhiệm vụ
Kotlin SELF, mức độ, bài học
Đã khóa
Săn lỗi
Săn lỗi
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION