You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Path.useLines()抛出IOException(Stream closed)的解决方法

解决Path.useLines()返回序列时流提前关闭的问题

你遇到的问题核心是Sequence的惰性求值特性和useLines()的自动关闭逻辑冲突:

问题代码

读取类实现

class PipeSeparatedItemsReader(private val filePath: Path) : ItemsReader {
    override fun readItems(): Sequence<ItemEntry> {
        return filePath.useLines { lines -> 
            lines.map { ItemEntry("A","B","C","D") } 
        }
    }
}

调用代码

val itemsPath = Path(...).resolve()
val itemsReader = PipeSeparatedItemsReader(itemsPath)

for (itemEntry in itemsReader.readItems())
    updateItem(itemEntry)

// 也曾尝试:itemsReader.readItems().forEach { ... }

问题原因

useLines()的设计是在lambda执行完毕后立即关闭文件流,但你返回的Sequence是惰性求值的——lambda执行时只是创建了序列对象,并没有真正开始读取文件。当lambda结束,useLines()关闭流后,后续遍历序列时自然会抛出"Stream closed"异常。

正确实现方式

用Kotlin的sequence构建器包裹useLines()调用,将流的生命周期与序列遍历绑定:

class PipeSeparatedItemsReader(private val filePath: Path) : ItemsReader {
    override fun readItems(): Sequence<ItemEntry> = sequence {
        filePath.useLines { lines ->
            // 通过yieldAll将转换后的元素逐个产出
            yieldAll(lines.map { ItemEntry("A", "B", "C", "D") })
        }
    }
}

为什么这样有效

  • sequence构建器创建的序列是惰性的,只有当开始遍历(比如for循环、forEach)时,才会执行内部的代码块。
  • 遍历过程中,useLines()会保持文件流打开,直到yieldAll完成所有元素的产出,或者遍历中途终止(比如break、异常),此时useLines()才会自动关闭流,完全符合你的预期。

内容的提问来源于stack exchange,提问作者Ondra Žižka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:30:58