1. 概述

本文将系统介绍在 Kotlin 中读取文件的常用方法,涵盖以下场景:

  • 整个文件内容读取为一个 String
  • 按行读取,返回 List<String>
  • 从绝对路径或项目资源(resources)中加载文件

这些方法各有适用场景,合理选择能避免踩坑,比如内存溢出或资源未释放等问题。✅

2. 文件读取方法详解

我们先准备一个测试文件 Kotlin.txt,内容如下:

Hello to Kotlin. It's:
1. Concise
2. Safe
3. Interoperable
4. Tool-friendly

该文件可放在项目目录下或 src/main/resources 中,根据调用方式决定路径写法。

下面逐一介绍不同读取方式。

2.1. forEachLine —— 行级遍历处理

适用于逐行处理大文件,无需一次性加载到内存。

特点:

  • 自动按行切割
  • 使用 UTF-8 编码(可指定)
  • 每行传入 lambda 处理
  • 文件自动关闭
fun readFileLineByLineUsingForEachLine(fileName: String) 
    = File(fileName).forEachLine { println(it) }

⚠️ 注意:此方法适合“只读+打印/处理”的场景,无法收集成集合返回。

2.2. useLines —— 安全获取行序列

forEachLine 类似,但可以将行数据转换为集合或其他结构,并在结束后自动关闭流。

fun readFileAsLinesUsingUseLines(fileName: String): List<String>
    = File(fileName).useLines { it.toList() }

✅ 推荐用于需要按行读取且返回集合的场景,尤其对大文件更安全。
❌ 不要在此 block 外引用 it(即 Sequence<String>),否则会抛异常。

2.3. bufferedReader —— 手动控制缓冲读取

返回标准 Java 的 BufferedReader,灵活性高,适合复杂逻辑。

fun readFileAsLinesUsingBufferedReader(fileName: String): List<String>
    = File(fileName).bufferedReader().readLines()

你也可以手动循环读取:

File(fileName).bufferedReader().use { reader ->
    var line: String?
    while (reader.readLine().also { line = it } != null) {
        println(line)
    }
}

✅ 优势:完全掌控读取过程
✅ 结合 use 可确保资源释放

2.4. readLines —— 简洁读取所有行

最简洁的方式,直接返回 List<String>

fun readFileAsLinesUsingReadLines(fileName: String): List<String> 
    = File(fileName).readLines()

⚠️ 警告:底层是一次性读入全部内容,不适用于大文件(如几百 MB 日志)。
✅ 小文件场景下非常方便,代码干净。

2.5. inputStream —— 原始字节流操作

通过 InputStream 获取原始字节,再转为字符串:

fun readFileAsTextUsingInputStream(fileName: String): String
    = File(fileName).inputStream().readBytes().toString(Charsets.UTF_8)

✅ 适合需要底层控制的场景
readBytes() 会把整个文件加载进内存,大文件有 OOM 风险

建议配合 use 使用以释放资源:

File(fileName).inputStream().use { 
    it.readBytes().toString(Charsets.UTF_8) 
}

2.6. readText —— 直接读取全文字符串

最简单的整文件读取方式:

fun readFileDirectlyAsText(fileName: String): String 
    = File(fileName).readText(Charsets.UTF_8)

✅ 一行搞定,适合配置文件、模板等小文本
⚠️ 内部限制最大 2GB,超限会抛异常
❌ 绝对不要用于日志、导出数据等大文件

2.7. getResource —— 读取 classpath 资源(URL)

用于读取打包后的资源文件(如 jar 内部),基于类路径查找:

fun readFileUsingGetResource(fileName: String): String? {
    return this::class.java.getResource(fileName)?.readText(Charsets.UTF_8)
}

示例调用:

readFileUsingGetResource("/Kotlin.txt") // 注意斜杠前缀

✅ 适用于 src/main/resources 下的静态资源
❌ 若文件不存在返回 null,需判空处理
📌 路径是相对 classpath 的,不是绝对路径

2.8. getResourceAsStream —— 读取资源流

更推荐的方式,返回 InputStream,更灵活且兼容性好:

fun readFileAsLinesUsingGetResourceAsStream(fileName: String): List<String>? {
    return this::class.java.getResourceAsStream(fileName)
        ?.bufferedReader()
        ?.readLines()
}

示例:

readFileAsLinesUsingGetResourceAsStream("/Kotlin.txt")

✅ 推荐用于读取 resources 目录下的文件
✅ 流式处理更省内存
❌ 同样需注意路径写法和空值判断

3. 总结与建议

方法 适用场景 是否推荐
forEachLine 逐行处理大文件
useLines 按行读取并返回集合 ✅✅(推荐)
bufferedReader 复杂读取逻辑
readLines 小文件转 List ✅(小文件)❌(大文件)
inputStream + readBytes 字节级操作 ⚠️ 注意内存
readText 小文件转 String ✅(<100MB)
getResource classpath 资源读取
getResourceAsStream 推荐的资源读取方式 ✅✅(首选)

📌 最佳实践建议

  • 小文件 → readText()readLines()
  • 大文件 → useLines()forEachLine()
  • 资源文件 → getResourceAsStream()
  • 需要编码控制 → 显式传入 Charsets.UTF_8 等参数

源码地址:GitHub repo


原始标题:Reading from a File in Kotlin