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

Kotlin使用CsvMapper解析大CSV文件遇Stream Closed异常如何解决?

问题

服务器生成的CSV报告文件包含10万+行数据,在Kotlin中使用CsvMapper读取该文件时遭遇IOException异常。实现代码如下:

//Declare the mapper object
private var csvMapper = CsvMapper().registerModule(KotlinModule())
        
//Generate Iterator
inline fun <reified T> getIterator(fileName: String): MappingIterator<T>? {
    csvMapper.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
    FileReader(fileName).use { reader ->
        return csvMapper
                       .readerFor(T::class.java)
                       .without(StreamReadFeature.AUTO_CLOSE_SOURCE)
                       .with(CsvSchema.emptySchema().withHeader())
                       .readValues<T>(reader)
    }
}
    
//Read the file using iterator
fun read(csvFile: String) {
    val iterator = getIterator<BbMembershipData>(csvFile)
    if (iterator != null) {
          while (iterator.hasNext()) {
                try {
                     val lineElement = iterator.next()
                     println(lineElement)
                } catch (e: RuntimeJsonMappingException) {
                    println("Iterator Exception: " + e.localizedMessage)
                }
          }
     }
}

打印10行数据后抛出如下异常:

Exception in thread "main" java.lang.RuntimeException: Stream closed
    at com.fasterxml.jackson.databind.MappingIterator._handleIOException(MappingIterator.java:420)
    at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:203)
    at Main$FileProcessor.read(Main.kt:39)
    at Main.main(Main.kt:54)
Caused by: java.io.IOException: Stream closed

请问如何避免该Stream Closed异常?

解决方案

问题核心是**FileReader在use块结束后被自动关闭**,而MappingIterator依赖这个已关闭的流工作,后续调用next()时必然抛出流关闭异常。

修改思路:将文件读取的生命周期与迭代器遍历逻辑绑定,确保流在遍历完成后才关闭。

修改后的代码示例:

private var csvMapper = CsvMapper().registerModule(KotlinModule())

// 调整逻辑,将遍历操作作为参数传入,保证流在遍历结束后才关闭
inline fun <reified T> processCsv(fileName: String, action: (T) -> Unit) {
    csvMapper.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
    FileReader(fileName).use { reader ->
        val iterator = csvMapper
            .readerFor(T::class.java)
            .without(StreamReadFeature.AUTO_CLOSE_SOURCE)
            .with(CsvSchema.emptySchema().withHeader())
            .readValues<T>(reader)
        
        while (iterator.hasNext()) {
            try {
                val lineElement = iterator.next()
                action(lineElement)
            } catch (e: RuntimeJsonMappingException) {
                println("Iterator Exception: " + e.localizedMessage)
            }
        }
    }
}

// 调用示例
fun read(csvFile: String) {
    processCsv<BbMembershipData>(csvFile) { lineElement ->
        println(lineElement)
    }
}

关键修改点:

  • 移除单独返回MappingIterator的逻辑,改为在use块内部完成整个CSV遍历操作
  • 通过高阶函数action传入具体行处理逻辑,确保流在遍历结束后才被use自动关闭
  • 保留原有异常处理逻辑,避免单条数据解析失败中断整个文件读取

内容的提问来源于stack exchange,提问作者Satyam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:30:48