(Kotlin/코틀린) 파일 입출력 — readText, writeText, forEachLine
1. 파일 읽기 — readText
파일 전체를 한 번에 문자열로 읽습니다.
import java.io.File
val file = File("data.txt")
// 전체 내용 읽기
val content = file.readText()
println(content)
// 인코딩 지정
val contentUtf8 = file.readText(Charsets.UTF_8)
// 줄 단위로 List<String> 반환
val lines = file.readLines()
lines.forEach { println(it) }
readText()는 파일을 메모리에 전부 올리므로 소용량 파일에 적합합니다.
2. 파일 쓰기 — writeText / appendText
val file = File("output.txt")
// 파일 생성 또는 덮어쓰기
file.writeText("Hello, Kotlin!\n")
file.writeText("두 번째 줄\n", Charsets.UTF_8)
// 파일에 내용 추가 (append)
file.appendText("추가된 줄\n")
// 줄 목록을 한 번에 쓰기
val lines = listOf("첫 번째", "두 번째", "세 번째")
File("list.txt").writeText(lines.joinToString("\n"))
3. forEachLine — 줄 단위 처리
파일을 한 줄씩 스트리밍으로 읽습니다. 대용량 파일에 적합합니다.
File("large.txt").forEachLine { line ->
println(line)
}
// 인코딩 지정
File("large.txt").forEachLine(Charsets.UTF_8) { line ->
if (line.startsWith("ERROR")) {
println("에러 발견: $line")
}
}
forEachLine은 내부적으로 BufferedReader를 사용하고 자동으로 닫습니다.
4. useLines — 시퀀스로 처리
Sequence<String>으로 줄을 처리합니다. 필터링, 변환 등 체이닝이 자연스럽습니다.
// 특정 조건 줄만 수집
val errorLines = File("app.log").useLines { lines ->
lines
.filter { it.contains("ERROR") }
.map { it.trim() }
.toList()
}
// 줄 수 세기
val lineCount = File("data.txt").useLines { it.count() }
// 첫 번째 매칭 줄 찾기
val firstError = File("app.log").useLines { lines ->
lines.firstOrNull { it.startsWith("ERROR") }
}
useLines 블록이 끝나면 파일이 자동으로 닫힙니다.
5. bufferedReader / bufferedWriter
세밀한 제어가 필요할 때 사용합니다.
// 읽기
File("data.txt").bufferedReader().use { reader ->
var line: String?
while (reader.readLine().also { line = it } != null) {
println(line)
}
}
// 쓰기
File("output.txt").bufferedWriter().use { writer ->
writer.write("첫 번째 줄")
writer.newLine()
writer.write("두 번째 줄")
writer.newLine()
}
use { } 블록이 끝나면 Closeable이 자동으로 닫힙니다 (try-finally 대체).
6. 바이너리 파일 — readBytes / writeBytes
// 이미지, PDF 등 바이너리 파일
val imageBytes = File("photo.jpg").readBytes()
println("파일 크기: ${imageBytes.size} bytes")
// 복사
File("photo_copy.jpg").writeBytes(imageBytes)
// 바이트 추가
File("data.bin").appendBytes(byteArrayOf(0x00, 0x01, 0x02))
7. 파일/디렉토리 유틸리티
val file = File("config.json")
// 존재 여부 / 타입 확인
println(file.exists()) // true/false
println(file.isFile) // 파일인지
println(file.isDirectory) // 디렉토리인지
println(file.length()) // 바이트 크기
println(file.name) // "config.json"
println(file.extension) // "json"
println(file.nameWithoutExtension) // "config"
// 디렉토리 생성
File("logs/2026").mkdirs() // 중간 디렉토리 포함 생성
// 디렉토리 내 파일 목록
File("logs").listFiles()?.forEach { println(it.name) }
// 확장자 필터링
File("src").walk()
.filter { it.extension == "kt" }
.forEach { println(it.path) }
8. 실전 패턴 — CSV 파일 파싱
data class Person(val name: String, val age: Int, val email: String)
fun parseCsv(path: String): List<Person> {
return File(path).useLines { lines ->
lines
.drop(1) // 헤더 제거
.filter { it.isNotBlank() }
.map { line ->
val parts = line.split(",")
Person(
name = parts[0].trim(),
age = parts[1].trim().toInt(),
email = parts[2].trim()
)
}
.toList()
}
}
// 사용
val people = parseCsv("people.csv")
people.forEach { println("${it.name} (${it.age})") }
9. 실전 패턴 — 로그 파일 분석
data class LogEntry(val timestamp: String, val level: String, val message: String)
fun analyzeLog(logPath: String): Map<String, Int> {
val levelCount = mutableMapOf<String, Int>()
File(logPath).forEachLine { line ->
// 예: [2026-08-01 12:00:00][ERROR] 서버 연결 실패
val match = Regex("""\[(.+?)]\[(\w+)] (.+)""").find(line)
if (match != null) {
val level = match.groupValues[2]
levelCount[level] = (levelCount[level] ?: 0) + 1
}
}
return levelCount
}
val stats = analyzeLog("app.log")
stats.forEach { (level, count) -> println("$level: $count건") }
// ERROR: 5건
// WARN: 23건
// INFO: 142건
10. 정리
| 메서드 | 용도 | 메모리 |
|---|---|---|
readText() |
전체 파일을 문자열로 | 전부 로드 |
readLines() |
전체 줄을 List로 | 전부 로드 |
writeText() |
파일에 덮어쓰기 | — |
appendText() |
파일에 추가 | — |
forEachLine {} |
줄 단위 스트리밍 처리 | 한 줄씩 |
useLines {} |
Sequence로 체이닝 처리 | 한 줄씩 |
bufferedReader() |
세밀한 읽기 제어 | 버퍼 |
readBytes() |
바이너리 파일 | 전부 로드 |
- 소용량:
readText()/readLines() - 대용량:
forEachLine {}/useLines {} use { }블록으로Closeable자동 해제 보장