Crear archivo csv en Scala

Estoy tratando de crear un csv archivo en Scala obteniendo datos en forma de JsValue de una tercera parte API. Mi método para guardar datos al archivo CSV es:

def saveToCSV(str:Seq[JsValue]) = {
  val outputFile = new BufferedWriter(new FileWriter("Result.csv"))
  val csvWriter = new CSVWriter(outputFile)
    val data = str.head
    data match {
      case JsObject(fields) => {
        var listOfRecords = new ListBuffer[Array[String]]()
        //val csvFields = Array("Open","High","Low","Close","Volume")
        //listOfRecords += csvFields
        fields.values.foreach(value => {
          val jsObject = value.asJsObject()
          val nameList = List(jsObject.fields("1. open").toString,jsObject.fields("2. high").toString,jsObject.fields("3. low").toString,jsObject.fields("4. close").toString,jsObject.fields("5. volume").toString)
          listOfRecords += Array(nameList.toString)
          csvWriter.writeAll(listOfRecords.toList.asInstanceOf)
          println("Written!")
          outputFile.close()
        })
      }
      case JsNull => println("Null")
    }

En el código anterior en línea **csvWriter.writeAll(listOfRecords.toList.asInstanceOf)** Estoy recibiendo esta excepción.

Exception in thread "main" java.lang.ClassCastException: class scala.collection.immutable.$colon$colon cannot be cast to class scala.runtime.Nothing$ (scala.collection.immutable.$colon$colon and scala.runtime.Nothing$ are in unnamed module of loader 'app')

Al quitar asInstanceOf desde csvWriter.writeAll(listOfRecords.toList.asInstanceOf) esta línea, tengo un error de tiempo compilado en escribirAll() método que dice que espera parámetro de tipo util. List[Array[String]]

¿Podría alguien ayudarme a resolver este problema?

Pregunta hecha hace 3 años, 4 meses, 29 días - Por debugdynamo46a0


3 Respuestas:

  • Tienes varios errores en tu código.

    1. asJsObject() es un método que no existe en JsValue. En lugar de eso deberías usar value.as[JsObject].
    2. jsObject.fields es de tipo Seq[(String, JsValue)]Así que no puedes llamar jsObject.fields("1. open"). En su lugar debe llamar: jsObject("1. open").toString
    3. Llamada listOfRecords.toList.asInstanceOf retornos null. Debe especificar a qué quiere convertirlo. Pero para convertirlo en un tipo java, puedes llamar: listOfRecords.toList.asJava. No olvides: import scala.jdk.CollectionConverters._

    El método completo es:

    import com.opencsv.CSVWriter
    import play.api.libs.json.{JsNull, JsObject, JsValue}
    
    import java.io.{BufferedWriter, FileWriter}
    import scala.collection.mutable.ListBuffer
    import scala.jdk.CollectionConverters._
    
    def saveToCSV(str: Seq[JsValue]) = {
      val outputFile = new BufferedWriter(new FileWriter("Result.csv"))
      val csvWriter = new CSVWriter(outputFile)
      val data = str.head
      data match {
        case JsObject(fields) => {
          var listOfRecords = new ListBuffer[Array[String]]()
          //val csvFields = Array("Open","High","Low","Close","Volume")
          //listOfRecords += csvFields
          fields.values.foreach(value => {
            val jsObject = value.as[JsObject]
            val nameList = List(jsObject("1. open").toString, jsObject("2. high").toString, jsObject("3. low").toString, jsObject("4. close").toString, jsObject("5. volume").toString)
            listOfRecords += Array(nameList.toString)
            csvWriter.writeAll(listOfRecords.toList.asJava)
            println("Written!")
            outputFile.close()
          })
        }
        case JsNull => println("Null")
      }
    }
    

    This will work under the assumed that the head of str contiene un JsObject, con los campos:

    • "1. open"
    • "2. alto"
    • "3. bajo"
    • "4. close"

    ¿Estás deliberadamente tomando sólo el primer elemento de la entrada a esta función? Tenga en cuenta que str.head es inseguro, en caso de que la secuencia esté vacía.

    Respondida el Dec 16, 2020 a las 19:06 - por binarybuilder

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando se debe a que estás tratando de hacer un cast incorrecto al utilizar asInstanceOf en la línea csvWriter.writeAll(listOfRecords.toList.asInstanceOf). En su lugar, puedes modificar esa línea de la siguiente manera:

    scala
    csvWriter.writeAll(listOfRecords.toList)
    

    Al eliminar asInstanceOf, la instrucción writeAll espera que le pases un parámetro de tipo List[Array[String]], por lo que al llamar a toList, obtienes el tipo correcto sin necesidad de un cast adicional.

    Además, te recomendaría que muevas la llamada a close() del archivo fuera del bucle foreach, para asegurarte de cerrar el archivo solo una vez al finalizar de escribir todos los registros:

    scala
    def saveToCSV(str: Seq[JsValue]) = {
      val outputFile = new BufferedWriter(new FileWriter("Result.csv"))
      val csvWriter = new CSVWriter(outputFile)
      val data = str.head
      data match {
        case JsObject(fields) => {
          var listOfRecords = new ListBuffer[Array[String]]()
          fields.values.foreach(value => {
            val jsObject = value.asJsObject()
            val nameList = List(jsObject.fields("1. open").toString, jsObject.fields("2. high").toString, jsObject.fields("3. low").toString, jsObject.fields("4. close").toString, jsObject.fields("5. volume").toString)
            listOfRecords += nameList.toArray
          })
          csvWriter.writeAll(listOfRecords.toList)
          println("Written!")
          outputFile.close()
        }
        case JsNull => println("Null")
      }
    }
    

    Con estos cambios, deberías poder escribir correctamente los datos en el archivo CSV sin errores de casting.

    Respondida el Dec 17, 2020 a las 19:03 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás encontrando se debe a que el método writeAll espera una lista de arreglos de cadenas (util.List[Array[String]]), pero estás intentando pasarle una lista de listas de cadenas (scala.collection.immutable.$colon$colon).

    Para resolver este problema, puedes convertir tu lista de listas de cadenas a una lista de arreglos de cadenas utilizando el método toArray de la siguiente manera:

    scala
    csvWriter.writeAll(listOfRecords.toList.map(_.toArray))
    

    Esto creará un nuevo arreglo para cada lista interna en listOfRecords y luego pasará la lista de arreglos al método writeAll.

    Aquí tienes el código actualizado con la corrección:

    scala
    def saveToCSV(str: Seq[JsValue]) = {
      val outputFile = new BufferedWriter(new FileWriter("Result.csv"))
      val csvWriter = new CSVWriter(outputFile)
    
      val data = str.head
    
      data match {
        case JsObject(fields) => {
          var listOfRecords = new ListBuffer[Array[String]]()
          //val csvFields = Array("Open","High","Low","Close","Volume")
          //listOfRecords += csvFields
          fields.values.foreach(value => {
            val jsObject = value.asJsObject()
            val nameList = List(jsObject.fields("1. open").toString, jsObject.fields("2. high").toString, jsObject.fields("3. low").toString, jsObject.fields("4. close").toString, jsObject.fields("5. volume").toString)
            listOfRecords += Array(nameList.toString)
          })
          csvWriter.writeAll(listOfRecords.toList.map(_.toArray))
          println("Written!")
          outputFile.close()
        }
        case JsNull => println("Null")
      }
    }
    

    Respondida el Dec 17, 2020 a las 19:14 - por Gemini

    Votos positivos: 0 | Votos negativos: 0