Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,11 @@ lazy val scala_libraries = (project in file("scala-libraries"))
"org.apache.logging.log4j" % "log4j-core" % "2.24.3" % Runtime,
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5",
"software.amazon.awssdk" % "s3" % "2.25.9",
"com.github.seratch" %% "awscala" % "0.9.2"
"com.github.seratch" %% "awscala" % "0.9.2",
"com.opencsv" % "opencsv" % "5.9",
"com.github.tototoshi" %% "scala-csv" % "2.0.0",
"org.apache.commons" % "commons-csv" % "1.12.0"

),
libraryDependencies ++= Seq(
"org.playframework" %% "play-slick" % LibraryVersions.playSlickVersion,
Expand Down
4 changes: 4 additions & 0 deletions scala-libraries/src/main/resources/persons.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
id,name
1,Jim
2,Bob
3,Mary
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.baeldung.csv.reader

import org.apache.commons.csv.CSVFormat

import java.io.{File, FileInputStream, InputStreamReader}
import scala.jdk.CollectionConverters.IterableHasAsScala

class ApacheCommonsCSVReader extends CommaSeparatedValuesReader {

override def read(file: File): CSVReadDigest = {
val in = new InputStreamReader(new FileInputStream(file))
val csvParser = CSVFormat.DEFAULT
.builder()
.setHeader()
.build()
.parse(in)
val result = CSVReadDigest(
csvParser.getHeaderNames.asScala.toSeq,
csvParser.getRecords.asScala.map(r => r.values().toSeq).toSeq
)
csvParser.close()
result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.baeldung.csv.reader

import java.io.File

object CSVReaders {

def main(args: Array[String]): Unit = {

val apacheCommonsCSVReader = new ApacheCommonsCSVReader
val simpleCSVReader = new SimpleCSVReader
val scalaCSVReader = new ScalaCSVReader
val openCSVReader = new OpenCSVReader

val file = new File(getClass.getResource("/persons.csv").getFile)

println(apacheCommonsCSVReader.read(file))
println(simpleCSVReader.read(file))
println(scalaCSVReader.read(file))
println(openCSVReader.read(file))

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.baeldung.csv.reader

import java.io.File

case class CSVReadDigest(headers: Seq[String], rows: Seq[Seq[String]])
trait CommaSeparatedValuesReader {

def read(file: File): CSVReadDigest

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.baeldung.csv.reader

import com.opencsv.CSVReader

import java.io.{File, FileInputStream, InputStreamReader}
import scala.annotation.tailrec

class OpenCSVReader extends CommaSeparatedValuesReader {

override def read(file: File): CSVReadDigest = {

val reader = new CSVReader(
new InputStreamReader(new FileInputStream(file))
)

@tailrec
def readLinesRecursively(
currentReader: CSVReader,
result: Seq[Seq[String]]
): Seq[Seq[String]] = {
currentReader.readNext() match {
case null => result
case line => readLinesRecursively(currentReader, result :+ line.toSeq)
}
}

val csvLines = readLinesRecursively(reader, List())
reader.close()

CSVReadDigest(
csvLines.head,
csvLines.tail
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.baeldung.csv.reader

import com.github.tototoshi.csv.CSVReader

import java.io.File

class ScalaCSVReader extends CommaSeparatedValuesReader {

override def read(file: File): CSVReadDigest = {
val reader = CSVReader.open(file)
val all = reader.all()
reader.close()
CSVReadDigest(all.head, all.tail)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.baeldung.csv.reader

import java.io.{BufferedReader, File, FileInputStream, InputStreamReader}
import scala.annotation.tailrec

class SimpleCSVReader extends CommaSeparatedValuesReader {

override def read(file: File): CSVReadDigest = {
val in = new InputStreamReader(new FileInputStream(file))
val bufferedReader = new BufferedReader(in)

@tailrec
def readLinesRecursively(
currentBufferedReader: BufferedReader,
result: Seq[Seq[String]]
): Seq[Seq[String]] = {
currentBufferedReader.readLine() match {
case null => result
case line =>
readLinesRecursively(
currentBufferedReader,
result :+ line.split(",").toSeq
)
}
}

val csvLines = readLinesRecursively(bufferedReader, List())

bufferedReader.close()

CSVReadDigest(
csvLines.head,
csvLines.tail
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.baeldung.csv.writer
import org.apache.commons.csv.{CSVFormat, CSVPrinter}

import java.io.{File, FileWriter}
import scala.util.Try

class ApacheCommonsCSVWriter extends CommaSeparatedValuesWriter {

override def write(
file: File,
headers: Seq[String],
rows: Seq[Seq[String]]
): Try[Unit] = Try {

val csvFormat = CSVFormat.DEFAULT
.builder()
.setHeader(headers: _*)
.build()

val out = new FileWriter(file)
val printer = new CSVPrinter(out, csvFormat)
rows.foreach(row => printer.printRecord(row: _*))
printer.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.baeldung.csv.writer

import java.io.File
import scala.util.Try

trait CommaSeparatedValuesWriter {

def write(
file: File,
headers: Seq[String],
rows: Seq[Seq[String]]
): Try[Unit]

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.baeldung.csv.writer

import java.io.File
import scala.util.{Failure, Success, Try}

object CsvWriters {

def main(args: Array[String]): Unit = {

val fileName = "foo.csv"
val headers = List("id", "name")
val rows = List(
List("1", "Manolis"),
List("2", "Thanasis"),
List("3", "Stefanos")
)

val simpleCSVWriter = new SimpleCSVWriter
val openCSVWriter = new OpenCSVWriter
val scalaCSVWriter = new ScalaCSVWriter
val apacheCommonsCSVWriter = new ApacheCommonsCSVWriter

handleFailure(
simpleCSVWriter.write(new File(s"simple-$fileName"), headers, rows)
)
handleFailure(
openCSVWriter.write(new File(s"openCSV-$fileName"), headers, rows)
)
handleFailure(
scalaCSVWriter.write(new File(s"scalaCSV-$fileName"), headers, rows)
)
handleFailure(
apacheCommonsCSVWriter.write(
new File(s"apacheCommons-$fileName"),
headers,
rows
)
)
}

private def handleFailure(tryWrite: Try[Unit]): Unit = {
tryWrite match {
case Success(_) =>
case Failure(exception) =>
println(
s"Something went wrong during CSV writing: ${exception.getMessage}"
)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.baeldung.csv.writer

import com.opencsv.CSVWriter

import java.io.{BufferedWriter, File, FileWriter}
import scala.jdk.CollectionConverters.IterableHasAsJava
import scala.util.Try

class OpenCSVWriter extends CommaSeparatedValuesWriter {

override def write(
file: File,
headers: Seq[String],
rows: Seq[Seq[String]]
): Try[Unit] = Try(
new CSVWriter(new BufferedWriter(new FileWriter(file)))
).flatMap((csvWriter: CSVWriter) =>
Try {
csvWriter.writeAll(
(headers +: rows).map(_.toArray).asJava,
false
)
csvWriter.close()
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.baeldung.csv.writer

import com.github.tototoshi.csv.CSVWriter

import java.io.File
import scala.util.Try

class ScalaCSVWriter extends CommaSeparatedValuesWriter {

override def write(
file: File,
headers: Seq[String],
rows: Seq[Seq[String]]
): Try[Unit] = Try {
val writer = CSVWriter.open(file)
writer.writeRow(headers)
writer.writeAll(rows)
writer.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.baeldung.csv.writer

import java.io.{File, PrintWriter}
import scala.util.Try

class SimpleCSVWriter extends CommaSeparatedValuesWriter {

override def write(
file: File,
headers: Seq[String],
rows: Seq[Seq[String]]
): Try[Unit] = Try {
val writer = new PrintWriter(file)
writer.println(headers.mkString(","))
rows.foreach(row => writer.println(row.mkString(",")))
writer.close()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.baeldung.csv.reader

import org.scalatest.matchers.should
import org.scalatest.wordspec.AnyWordSpec

import java.io.{File, PrintWriter}
import java.nio.file.{Files, Path}
import java.util.UUID

class ScalaCSVReadersUnitTest extends AnyWordSpec with should.Matchers {

"SimpleCSVReader" should {
"read a csv file" in {
commonTestBody(new SimpleCSVReader, randomTmpFile().toFile)
}
}

"ScalaCSVReader" should {
"read a csv file" in {
commonTestBody(new ScalaCSVReader, randomTmpFile().toFile)
}
}

"OpenCSVReader" should {
"read a csv file" in {
commonTestBody(new OpenCSVReader, randomTmpFile().toFile)
}
}

"ApacheCommonsCSVReader" should {
"read a csv file" in {
commonTestBody(new ApacheCommonsCSVReader, randomTmpFile().toFile)
}
}

private def commonTestBody(
testee: CommaSeparatedValuesReader,
file: File
): Unit = {
val result = testee.read(file)
assert(result.headers === List("column1", "column2"))
assert(
result.rows === List(
List("1.1", "1.2"),
List("2.1", "2.2")
)
)
}

private def randomTmpFile(): Path = {
val path = Files.createTempFile(
s"persons-${UUID.randomUUID().toString.take(8)}",
"csv"
)
val writer = new PrintWriter(path.toFile)
writer.println(List("column1", "column2").mkString(","))
writer.println(List("1.1", "1.2").mkString(","))
writer.println(List("2.1", "2.2").mkString(","))
writer.close()
path
}

}
Loading