Examples¶
This page demonstrates common use cases for kotlin-dsv.
Streaming Large Files¶
Use encodeToSink
and decodeFromSource
to work with streams instead of
loading everything into memory:
// Generate a sequence of products (could be from a database cursor, etc.)
val productSequence =
generateSequence(1) { if (it < 100) it + 1 else null }
.map { Product(it, "Product $it", it * 9.99) }
// Write to a buffer - elements are serialized as the sequence is iterated
val buffer = Buffer()
Csv.encodeToSink(productSequence, buffer)
// Read from the buffer - elements are deserialized as the sequence is consumed
val decodedSequence = Csv.decodeFromSource<Product>(buffer)
decodedSequence.forEach { product ->
// Process product...
}
This is particularly useful when working with large files:
// Write to file
SystemFileSystem.sink(Path("data.csv")).buffered().use { sink ->
Csv.encodeToSink(myData, sink)
}
// Read from file
val data =
SystemFileSystem.source(Path("data.csv")).buffered().use { source ->
Csv.decodeFromSource<MyData>(source).forEach { item ->
// Process item...
}
}
TSV Format¶
Work with tab-separated values using the pre-configured Tsv
format:
// TSV (tab-separated values) format
val tsv = Tsv.encodeToString(records)
val decoded = Tsv.decodeFromString<Record>(tsv)
Custom Delimiters¶
Create a custom format with any delimiter:
// Custom delimiter (pipe-separated values)
val format = DsvFormat(scheme = DsvScheme(delimiter = '|'))
val psv = format.encodeToString(items)
val decoded = format.decodeFromString<Data>(psv)
You can also customize the quote character and line endings:
val format =
DsvFormat(
scheme =
DsvScheme(
delimiter = ';',
quote = '\'',
writeCrlf = false, // Use Unix-style line endings
)
)
Naming Strategies¶
Transform property names to match different naming conventions:
@Serializable
data class User(val firstName: String, val lastName: String, val emailAddress: String)
val format = DsvFormat(Csv.scheme, namingStrategy = DsvNamingStrategy.SnakeCase)
val users =
listOf(User("Amara", "Okafor", "amara@example.com"), User("Chen", "Wei", "chen@example.com"))
val csv = format.encodeToString(users)
// CSV will have headers: first_name,last_name,email_address
val decoded = format.decodeFromString<User>(csv)
Available strategies:
DsvNamingStrategy.Identity
- No transformation (default)DsvNamingStrategy.SnakeCase
- ConvertscamelCase
tosnake_case
DsvNamingStrategy.KebabCase
- ConvertscamelCase
tokebab-case
DsvNamingStrategy.PascalCase
- ConvertscamelCase
toPascalCase
DsvNamingStrategy.TitleCaseWords
- ConvertscamelCase
toTitle Case Words
DsvNamingStrategy.SentenceCaseWords
- ConvertscamelCase
toSentence case words
DsvNamingStrategy.LowercaseWords
- ConvertscamelCase
tolowercase words
DsvNamingStrategy.UppercaseWords
- ConvertscamelCase
toUPPERCASE WORDS
DsvNamingStrategy.Composite
- Chain multiple strategies together
You can also implement custom strategies by extending DsvNamingStrategy.
Handling Missing or Extra Columns¶
Handle CSVs with incomplete or extra columns:
val format =
DsvFormat(scheme = Csv.scheme, treatMissingColumnsAsNull = true, ignoreUnknownKeys = true)
// CSV has extra column 'extra' and missing column 'description'
val csv =
"""
id,name,extra
1,Item A,ignored
2,Item B,also ignored
"""
.trimIndent()
val decoded = format.decodeFromString<PartialData>(csv)
// Missing 'description' column is treated as null
// Extra 'extra' column is ignored
Enum Serialization¶
Serialize enums by name or ordinal:
@Serializable
enum class Status {
ACTIVE,
INACTIVE,
PENDING,
}
@Serializable data class Item(val id: Int, val status: Status)
val items = listOf(Item(1, Status.ACTIVE), Item(2, Status.PENDING))
// By name (default)
val csvByName = Csv.encodeToString(items)
// Output: id,status\n1,ACTIVE\n2,PENDING
// By ordinal
val formatByOrdinal = DsvFormat(scheme = Csv.scheme, writeEnumsByName = false)
val csvByOrdinal = formatByOrdinal.encodeToString(items)
// Output: id,status\n1,0\n2,2