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
相关产品推荐
相关产品推荐

