利用Kotlin中的CsvMapper解析大型CSV文件

szqfcxe2  于 2022-12-13  发布在  Kotlin
关注(0)|答案(1)|浏览(259)

我有一个由服务器生成的CSV文件作为报告。CSV文件有超过100k行的文本。我正在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”异常?

wlwcrazw

wlwcrazw1#

CsvMapper的工作方式是 * lazely * 读取,而不是在调用readValues时阅读整个文件。
当到达use块的末尾时,基本上还没有读取任何内容!只有在开始使用迭代器时才开始阅读文件,但那时文件已经关闭了!
因此,需要打开和关闭文件的是read,而不是getIterator

//Generate Iterator
inline fun <reified T> getIterator(reader: Reader): MappingIterator<T>? {
    csvMapper.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
    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) {
    FileReader(csvFile).use { reader ->
        val iterator = getIterator<BbMembershipData>(reader)
        if (iterator != null) {
            while (iterator.hasNext()) {
                try {
                    val lineElement = iterator.next()
                    println(lineElement)
                } catch (e: RuntimeJsonMappingException) {
                    println("Iterator Exception: " + e.localizedMessage)
                }
            }
        }
    }
}

注意use块的末尾是如何变化的,即您完成阅读整个文件的位置。

相关问题