跳至正文

📁 檔案輸入輸出

📖 什麼是檔案輸入輸出?

**檔案輸入輸出(File I/O)**是讀取和寫入檔案的作業。對於資料儲存、設定管理、日誌記錄等都是必不可少的!

💡 讀取檔案

完整讀取

import java.io.File

fun main() {
// 將整個檔案讀取為字串
val content = File("data.txt").readText()
println(content)

// 將檔案讀取為行列表
val lines = File("data.txt").readLines()
for (line in lines) {
println(line)
}
}

安全讀取

import java.io.File

fun readFileSafe(filename: String): String? {
return try {
File(filename).readText()
} catch (e: Exception) {
println("讀取檔案失敗:${e.message}")
null
}
}

fun main() {
val content = readFileSafe("data.txt")
if (content != null) {
println("內容:$content")
} else {
println("無法讀取檔案")
}
}

逐行處理

import java.io.File

fun main() {
// 記憶體效率高(適合大檔案)
File("data.txt").forEachLine { line ->
println(line)
}

// useLines - 自動關閉
val lineCount = File("data.txt").useLines { lines ->
lines.count()
}
println("總行數:$lineCount")
}

✏️ 寫入檔案

覆寫

import java.io.File

fun main() {
// 寫入文字
File("output.txt").writeText("您好\n這是 Kotlin!")

// 逐行寫入
val lines = listOf("第一行", "第二行", "第三行")
File("output.txt").writeText(lines.joinToString("\n"))
}

追加

import java.io.File

fun main() {
val file = File("log.txt")

// 追加
file.appendText("日誌 1\n")
file.appendText("日誌 2\n")
file.appendText("日誌 3\n")
}

安全寫入

import java.io.File

fun writeFileSafe(filename: String, content: String): Boolean {
return try {
File(filename).writeText(content)
true
} catch (e: Exception) {
println("寫入檔案失敗:${e.message}")
false
}
}

fun main() {
if (writeFileSafe("data.txt", "Hello Kotlin!")) {
println("檔案儲存完成")
}
}

🎯 實戰範例

簡單記事本

import java.io.File

class SimpleNotebook(private val filename: String) {
private val file = File(filename)

fun write(content: String) {
file.writeText(content)
println("儲存完成")
}

fun append(content: String) {
file.appendText("$content\n")
println("新增完成")
}

fun read(): String {
return if (file.exists()) {
file.readText()
} else {
"檔案不存在"
}
}

fun clear() {
file.writeText("")
println("內容已刪除")
}
}

fun main() {
val notebook = SimpleNotebook("mynotes.txt")

notebook.write("第一則筆記")
notebook.append("第二則筆記")
notebook.append("第三則筆記")

println("\n=== 筆記內容 ===")
println(notebook.read())
}

日誌記錄器

import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

class Logger(private val filename: String) {
private val file = File(filename)
private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

fun log(message: String) {
val timestamp = LocalDateTime.now().format(formatter)
file.appendText("[$timestamp] $message\n")
}

fun info(message: String) = log("INFO: $message")
fun error(message: String) = log("ERROR: $message")
fun warn(message: String) = log("WARN: $message")

fun readLogs(): String {
return if (file.exists()) {
file.readText()
} else {
"無日誌"
}
}
}

fun main() {
val logger = Logger("app.log")

logger.info("應用程式啟動")
logger.warn("記憶體不足")
logger.error("連線失敗")

println(logger.readLogs())
}

CSV 檔案處理

import java.io.File

data class Person(val name: String, val age: Int, val city: String)

object CsvHandler {
fun writeCsv(filename: String, people: List<Person>) {
val csv = StringBuilder()
csv.append("姓名,年齡,城市\n")

for (person in people) {
csv.append("${person.name},${person.age},${person.city}\n")
}

File(filename).writeText(csv.toString())
}

fun readCsv(filename: String): List<Person> {
val file = File(filename)
if (!file.exists()) return emptyList()

val lines = file.readLines()
if (lines.isEmpty()) return emptyList()

return lines.drop(1).map { line ->
val parts = line.split(",")
Person(parts[0], parts[1].toInt(), parts[2])
}
}
}

fun main() {
val people = listOf(
Person("張三", 25, "台北"),
Person("李四", 30, "高雄"),
Person("王五", 28, "台中")
)

// 儲存 CSV
CsvHandler.writeCsv("people.csv", people)
println("CSV 儲存完成")

// 讀取 CSV
val loaded = CsvHandler.readCsv("people.csv")
println("\n=== CSV 內容 ===")
loaded.forEach { println(it) }
}

設定檔管理

import java.io.File

class Config(private val filename: String) {
private val settings = mutableMapOf<String, String>()

init {
load()
}

private fun load() {
val file = File(filename)
if (file.exists()) {
file.forEachLine { line ->
val parts = line.split("=")
if (parts.size == 2) {
settings[parts[0].trim()] = parts[1].trim()
}
}
}
}

fun save() {
val content = settings.entries.joinToString("\n") {
"${it.key}=${it.value}"
}
File(filename).writeText(content)
}

fun set(key: String, value: String) {
settings[key] = value
}

fun get(key: String): String? {
return settings[key]
}

fun getAll(): Map<String, String> {
return settings.toMap()
}
}

fun main() {
val config = Config("app.config")

// 儲存設定
config.set("host", "localhost")
config.set("port", "8080")
config.set("timeout", "3000")
config.save()

// 讀取設定
println("Host: ${config.get("host")}")
println("Port: ${config.get("port")}")

println("\n=== 所有設定 ===")
config.getAll().forEach { (key, value) ->
println("$key = $value")
}
}

📂 檔案/目錄管理

檔案資訊

import java.io.File

fun main() {
val file = File("data.txt")

println("存在:${file.exists()}")
println("檔案:${file.isFile}")
println("目錄:${file.isDirectory}")
println("大小:${file.length()} bytes")
println("絕對路徑:${file.absolutePath}")
println("名稱:${file.name}")
println("上層資料夾:${file.parent}")
}

目錄操作

import java.io.File

fun main() {
// 建立目錄
val dir = File("mydata")
dir.mkdir()

// 檔案列表
dir.listFiles()?.forEach { file ->
println("${file.name} (${if (file.isDirectory) "資料夾" else "檔案"})")
}

// 尋找子檔案
dir.walk().forEach { file ->
println(file.absolutePath)
}
}

複製/刪除檔案

import java.io.File

fun main() {
val source = File("source.txt")
val dest = File("dest.txt")

// 複製
source.copyTo(dest, overwrite = true)

// 移動
source.renameTo(File("moved.txt"))

// 刪除
dest.delete()

// 刪除整個目錄
File("mydata").deleteRecursively()
}

🤔 常見問題

Q1. 如果檔案不存在?

**A:**必須進行例外處理!

fun readFileSafe(filename: String): String {
val file = File(filename)

if (!file.exists()) {
return "檔案不存在"
}

return try {
file.readText()
} catch (e: Exception) {
"讀取失敗:${e.message}"
}
}

Q2. 大檔案怎麼辦?

**A:**逐行處理!

// ❌ 有記憶體不足的風險
val content = File("huge.txt").readText()

// ✅ 逐行處理
File("huge.txt").forEachLine { line ->
processLine(line)
}

Q3. 路徑分隔符號?

**A:**使用 File.separator!

// ❌ 每個作業系統不同
val path = "data/files/text.txt"

// ✅ 與作業系統無關
val file = File("data", "files").resolve("text.txt")
// 或
val path2 = listOf("data", "files", "text.txt").joinToString(File.separator)

🎬 結語

使用檔案輸入輸出來儲存和管理資料吧!

重點整理:
✅ 使用 readText() 讀取檔案
✅ 使用 writeText() 寫入檔案
✅ 使用 forEachLine() 進行逐行處理
✅ 使用 exists() 確認檔案是否存在
✅ 必須進行例外處理

下一步:在正規表示式中了解模式匹配!