I am trying to add column
to the end of a file without changing the contents using SuperCSV and kotlin.
I cannot use CSVWriter due to limitation of resources.
So, my idea is to read from the original file row by row and add that to a string and have the result be used as a byte array.
fun addColumnToCSV(csvData: ByteArray, columnName: String, columnValue: String): ByteArray {
val prefs = CsvPreference.Builder(CsvPreference.STANDARD_PREFERENCE)
.useQuoteMode(NormalQuoteMode()).build()
val mapReader = CsvMapReader(BufferedReader(InputStreamReader(csvData.inputStream())), prefs)
val readHeader = mapReader.getHeader(true)
var row = mapReader.read(*readHeader)
var csv: String = readHeader.joinToString(",", postfix = ",$columnName\n")
while (row != null) {
val rowValue=readHeader.map { header-> row.getOrDefault(header,"\\s") }
csv += rowValue.joinToString(",", postfix = ",$columnValue\n")
row = mapReader.read(*readHeader)
}
csv = csv.trim()
mapReader.close()
return csv.toByteArray()
}
So, I have an example here and written a test for it.
@Test
fun `should add extra column in csv data when there are missing values`() {
val columnName = "ExtraColumn"
val columnValue = "Value"
val expectedCSV = "Name,LastName,$columnName\n" +
"John,Doe,$columnValue\n" +
"Jane,,$columnValue"
val csvData = "Name,LastName\n" + "John,Doe\n" + "Jane,"
val csv = addColumnToCSV(csvData.toByteArray(), columnName, columnValue)
Assertions.assertThat(String(csv)).isEqualTo(expectedCSV)
}
This test fails because the actual of csv
data is
Name,LastName,ExtraColumn
John,Doe,Value
Jane,null,Value
I want it to be this, so that I am not changing the existing values that are present in the csv file.
Name,LastName,ExtraColumn
John,Doe,Value
Jane,,Value
I have tried with row.getOrDefault(header,"")
its still the same result. How do I achieve this?
The problem seems to be on this line:
val rowValue=readHeader.map { header-> row.getOrDefault(header,"\\s") }
Without testing this, I would say that there's a null
in row at index LastName
, hence default value in getOrDefault
is not applied because map contains the key.
Please try something like this:
val rowValue=readHeader.map { header-> row.getOrDefault(header,"\\s") ?: "" }