Skip to content

jsoizo/kotlin-csv

Repository files navigation

kotlin-csv

Version License: Apache License 2.0 codecov CodeFactor

Pure Kotlin Multiplatform CSV reader and writer.

Setup

Gradle (Kotlin DSL)

implementation("com.jsoizo:kotlin-csv:2.0.0")

The multiplatform artifact resolves JVM, JS, and supported Kotlin/Native variants from Kotlin Multiplatform projects. Published Native targets are macosArm64, iosArm64, iosSimulatorArm64, linuxX64, linuxArm64, and mingwX64.

Single-platform Gradle projects can also depend on the platform artifact directly, for example kotlin-csv-jvm, kotlin-csv-js, kotlin-csv-macosarm64, or kotlin-csv-linuxx64.

Gradle (Groovy DSL)

implementation 'com.jsoizo:kotlin-csv:2.0.0'

Maven

<dependency>
  <groupId>com.jsoizo</groupId>
  <artifactId>kotlin-csv-jvm</artifactId>
  <version>2.0.0</version>
</dependency>
<dependency>
  <groupId>com.jsoizo</groupId>
  <artifactId>kotlin-csv-js</artifactId>
  <version>2.0.0</version>
</dependency>

SNAPSHOT builds

Snapshots of the next development version are published to Sonatype Central Portal Snapshots from the active development branch. SNAPSHOTs are unstable and may change at any time, but they let you try in-progress changes early.

Add the snapshots repository to your build, then declare the dependency with the corresponding -SNAPSHOT version (see the active development branch's build.gradle.kts for the current value, for example 2.0.0-SNAPSHOT).

Gradle (Kotlin DSL)

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        mavenCentral()
        maven("https://central.sonatype.com/repository/maven-snapshots/") {
            mavenContent { snapshotsOnly() }
        }
    }
}
// build.gradle.kts
implementation("com.jsoizo:kotlin-csv:<VERSION>-SNAPSHOT")

Quick start

The DSL builders return reusable, stateless instances; create them once and share them across calls.

import com.jsoizo.kotlincsv.csvReader
import com.jsoizo.kotlincsv.csvWriter
import com.jsoizo.kotlincsv.reader.readFromFile
import com.jsoizo.kotlincsv.reader.withHeader
import com.jsoizo.kotlincsv.writer.writeToFile

val reader = csvReader()
val writer = csvWriter()

Read

// From a String — eager
val rows: List<List<String>> = reader.readAll("a,b,c\nd,e,f")

// From a File — lambda owns the open resource and closes it on exit
reader.readFromFile(File("data.csv")) { rows ->
    rows.forEach { println(it) }
}

// With a header row (returns LinkedHashMap to preserve column order)
reader.readFromFile(File("data.csv")) { rows ->
    val records = rows.withHeader().toList()
    println(records.first()["id"])
}

reader.readFromFile(...) accepts String paths, kotlinx.io.files.Path, and (on JVM) java.io.File. The block receives a cold Sequence<List<String>>; take(n) and friends short-circuit cleanly without parsing the rest of the file. For in-memory streams use reader.read(source) (commonMain kotlinx.io.Source) or reader.read(stream) (JVM java.io.InputStream).

Write

val rows = listOf(
    listOf("a", "b", "c"),
    listOf("d", "e", "f"),
)

// To a String — eager
val csv: String = writer.writeAll(rows)

// To a File
writer.writeToFile(rows, File("out.csv"))

writer.writeToFile(...) accepts String paths, kotlinx.io.files.Path, and (on JVM) java.io.File. For in-memory streams use writer.write(rows, sink) (commonMain kotlinx.io.Sink) or writer.write(rows, stream) (JVM java.io.OutputStream). Both Sequence<List<String>> and List<List<String>> are accepted as the row source.

Configuration

Reader and writer share a CsvDialect value object that holds the four characters defining the CSV format itself: delimiter, quoteChar, escapeChar, lineTerminator. Format-independent policies stay on the respective Config.

val tsvReader = csvReader {
    dialect = CsvDialect.TSV
    skipEmptyLine = true
}

val customWriter = csvWriter {
    dialect = CsvDialect(delimiter = ';', escapeChar = '\\')
    quoteMode = WriteQuoteMode.ALL
}
Reader option Default Description
dialect CsvDialect.RFC4180 Shared CSV format (delimiter / quote / escape / line terminator).
skipEmptyLine false Drop rows that are entirely empty before the field-count check.
excessFieldsRowBehaviour ERROR What to do when a row has more fields than the first row: ERROR / IGNORE / TRIM.
insufficientFieldsRowBehaviour ERROR What to do when a row has fewer fields: ERROR / IGNORE / EMPTY_STRING.

CsvFieldNumDifferentException.rowNum counts CSV rows after reader filters such as skipEmptyLine; it is not a physical source line number.

Writer option Default Description
dialect CsvDialect.RFC4180 Shared CSV format (delimiter / quote / escape / line terminator).
outputLastLineTerminator true Emit a trailing line terminator after the final row.
quoteMode CANONICAL When to wrap fields in quoteChar: CANONICAL (only when needed), ALL, or NON_NUMERIC.

Charset is JVM-only and is passed as an argument on the I/O call:

reader.readFromFile(File("data.csv"), charset = "Shift_JIS") { it.toList() }
writer.writeToFile(rows, File("out.csv"), charset = "UTF-16LE")

commonMain and JS overloads are UTF-8 only.

BOM stripping on read defaults to ON (matches Excel-produced files):

reader.readFromFile(File("data.csv"), options = CsvReadIoOptions(stripBom = false))

writer.writeToFile(rows, File("out.csv"), options = CsvWriteIoOptions(prependBom = true))

More

  • Migration from kotlin-csv 1.x: see V2_MIGRATION_GUIDE.md.
  • API documentation: generated by Dokka — ./gradlew dokkaHtml outputs HTML to build/dokka/html/.
  • Change Logs: see GitHub releases.

Miscellaneous

🤝 Contributing

Contributions, issues and feature requests are welcome! If you have questions, ask away in Kotlin Slack's kotlin-csv room.

💻 Development

git clone git@github.com:jsoizo/kotlin-csv.git
cd kotlin-csv
./gradlew check

📝 License

Copyright © 2024 jsoizo. This project is licensed under Apache 2.0.

Acknowledgments

This project was originally created by @doyaaaaaken. The initial work and contributions are greatly appreciated.

About

Pure Kotlin CSV Reader/Writer

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

Contributors

Languages