Scala CSV file (stream) reader
CsvReader is simple CSV reader with pure Scala.
The reader supports:
-
arbitrary case class for record data
-
file with or without header line
-
setting either continue or stop after error during parsing a record
-
setting different delimiter character
-
error handling
-
record handling
Record data class is a case class. For example:
case class TestData1(i: Int, s: String, d: Double)
Some parameters may be Option, For example
case class TestData2(i: Int, s: Option[String], d: Double) {
def this(params: Seq[String]) {
this(params(0).toInt,
if (params(1).isEmpty)
None
else
Some(params(1)),
params(2).toDouble
)
}
}
Note in this case the auxiliary constructor should be defined!
def recordHandler(record:TestData]:Unit={
...
}
def errorHandler(error:String]:Unit={
...
}
CsvReader.reader[TestData](Source.fromFile("data.csv"), recordHandler, errorHandler)
.parse()
or
// Empty record handler
def handler(testData: TestData1): Unit = {}
val list = CsvReader.reader[TestData1](Source.fromResource("test-data1.csv"), handler, errorHandler).toList
Custom transformer allows to customize creating an object.
recordHandler method should be called for each created object.
errorHandler method should be called for each error during creating object.
Example:
def transformer(line: Seq[String], recordHandler: TestData1 => Unit, errorHandler: String => Unit): TestData1 = {
try {
val data = TestData1(333, "test", 77.12)
recordHandler(data)
data
} catch {
case e: Exception =>
errorHandler(e.getMessage)
throw e
}
}
See CsvReaderTest test("customTransformer") and test("customTransformer with error")
CsvStreamReader is CSV reader with using the Akka stream.
The reader supports:
-
arbitrary case class for record data
-
file with or without header line
-
setting either continue or stop after error during parsing a record
-
setting different delimiter character
-
error handling
-
record handling
Record data class is a case class. For example:
case class TestData1(i: Int, s: String, d: Double)
Some parameters may be Option, For example
case class TestData2(i: Int, s: Option[String], d: Double) {
def this(params: Seq[String]) {
this(params(0).toInt,
if (params(1).isEmpty)
None
else
Some(params(1)),
params(2).toDouble
)
}
}
Note in this case the auxiliary constructor should be defined!
def recordHandler(record:TestData]:Unit={
...
}
def errorHandler(error:String]:Unit={
...
}
implicit val actorSystem: ActorSystem = ActorSystem("CsvStreamReaderTest")
implicit val materializer: ActorMaterializer = ActorMaterializer()
val reader = CsvStreamReader.reader(Source.fromResource("test-data1.csv"), recordHandler, errorHandler)
Await.ready(reader.run(), Duration.Inf)
source.close()
actorSystem.terminate()
def errorHandler(error:String]:Unit={
...
}
implicit val actorSystem: ActorSystem = ActorSystem("CsvStreamReaderTest")
implicit val materializer: ActorMaterializer = ActorMaterializer()
val list = ListBuffer.empty[TestData1]
val reader = CsvStreamReader.reader(Source.fromResource("test-data1.csv"),
item => list += item,
errorHandler)
Await.ready(reader.run(), Duration.Inf)
println(s"list.length=${list.length}")
source.close()
actorSystem.terminate()