android - 跳过 CSV 解析器中的每第 N 行

标签 android csv kotlin opencsv

我正在使用 opencsv 解析器。在我的 csv 文件中,大约有 100,000 行。阅读它们需要太多时间。如何跳过并读取每第 N 行(例如每第 30 行)?

private suspend fun readCSVRides(folder: String): MutableList<RideDataCsv>? = withContext(Dispatchers.IO) {

    val path = getExternalFilesDir(null)!!.path + "/" + folder + "/" + "measurements.csv"

    var segments: MutableList<RideDataCsv>? = null

    var fileReader: BufferedReader? = null
    val csvToBean: CsvToBean<RideDataCsv>?

    try {
        fileReader = BufferedReader(FileReader(path))
        csvToBean = CsvToBeanBuilder<RideDataCsv>(fileReader)
            .withType(RideDataCsv::class.java)
            .withIgnoreLeadingWhiteSpace(true)
            .withIgnoreEmptyLine(true)
            .build()

        segments = csvToBean.parse()
       
    } catch (e: Exception) {
        println("Reading CSV Error!")
        e.printStackTrace()
    } finally {
        try {
            fileReader!!.close()
        } catch (e: IOException) {
            println("Closing fileReader/csvParser Error!")
            e.printStackTrace()
        }
    }
    segments
}

最佳答案

您可以实现一个Reader,它会跳过输入中的每n行并包装您的fileReader,如下所示:

fileReader = SkipReader(BufferedReader(FileReader(path)), skipEvery = 30)

下面是如何实现它的示例:

import java.io.BufferedReader
import java.io.StringReader
import java.io.Reader

class SkipReader(
    private val input: Reader,
    private val skipEvery: Int
) : Reader(input) {

    private var linesToSkip = skipEvery - 1
    private var isSkipping = false
    
    override fun read(cbuf: CharArray, offset: Int, len: Int): Int {
        var bytesRead = 0
        while (bytesRead < len) {
            val value = input.read()
            if (value == -1) {
                break
            }
            val c = value.toChar()
            if (c == '\n') {
                if (linesToSkip == 0) {
                    linesToSkip = skipEvery - 1
                    isSkipping = false
                } else {
                    isSkipping = true
                }
                if (isSkipping) {
                    linesToSkip--
                }
            }
            if (!isSkipping) {
                cbuf[offset + bytesRead] = c
                bytesRead++
            }
        }
        return if (bytesRead > 0) bytesRead else -1
    }
    
    override fun close() {
        input.close()
    }
}

通过重写其他方法来提高性能可能是一个好主意,但不仅仅是 readclose,因为它们是唯一需要重写的方法。另外,一次读取多个字符而不是在 input.read() 中逐一读取它们也可能有所帮助,但是 BufferedReader 已经可以很好地处理它。

测试几行:

fun main() {
    val csvText = 
        """
            Line 1
            Line 2
            Line 3
            Line 4
            Line 5
            Line 6
            Line 7
        """.trimIndent()
    val reader = SkipReader(BufferedReader(StringReader(csvText)), skipEvery = 2)
    for (line in reader.readLines()) {
        println(line)
    }
}

结果:

Line 1
Line 3
Line 5
Line 7

关于android - 跳过 CSV 解析器中的每第 N 行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65378950/

相关文章:

sql - 将子字符串与空格分隔的值分开

csv - 创建一个 HIVE 表,根据列中的值从 HDFS 中的 .csv 中过滤数据

java - 如何在Java中通过Web Scraping获取多个HTML表的数据

java - 如何使用 StickerView 撤消和重做功能?

clojure - 如何在Kotlin中无限循环地懒惰地循环列表?

firebase - Kotlin/Firebase获取对象列表

kotlin - 如何发出订阅结果

android - session 应用程序 : Error launching Activity in Android Studio

java - 在java程序中使用android aapt

android - 支持的 Cordova Android 版本