当前位置: 首页 > 知识库问答 >
问题:

如何在scala中写入csv文件?

左丘边浩
2023-03-14

我试图将数据写入csv文件,我创建了四列作为

val csvFields = Array("Serial Number", "Record Type", First File value", Second file value") ', 

除了序列号,其他三个字段是列表

Second_file_value = List ("B", "gjgbn", "fgbhjf", "dfjf")

First_File_Value=List(“A”、“abhc”、“agch”、“mknk”)

Record_type=List('1','2',3','4')

 val outputFile = new BufferedWriter(new FileWriter("Resulet.csv")
 val csvWriter = new CSVWriter(outputFile)
 val listOfRecords = new ListBuffer[Array[String]]()
 listOfRecords :+ csvFields

我使用这个循环写入列

for ( i <- 1 until 30){
listOfRecords += Array(i.toString, Record_type , First_File_Value , Second_file_value )}
csvWriter.writeAll(listOfRecords.toList)
output.close()

我面临的问题是csv文件填充了30行相同的值(第一行值),列表中的值没有被迭代。

任何参考资料也会有所帮助


共有1个答案

史弘博
2023-03-14

如果没有完整的示例(如在编译Main文件中),就无法解释为什么一遍又一遍地得到同一行。你发布的代码片段单独来看是正确的。

scala> val lb: ListBuffer[Array[String]] = new ListBuffer[Array[String]]()
lb: scala.collection.mutable.ListBuffer[Array[String]] = ListBuffer()

scala> for (i <- 1 until 30){lb += Array(i.toString)}

scala> lb.toList
res5: List[Array[String]] = List(Array(1), Array(2), Array(3), Array(4), Array(5), Array(6), Array(7), Array(8), Array(9), Array(10), Array(11), Array(12), Array(13), Array(14), Array(15), Array(16), Array(17), Array(18), Array(19), Array(20), Array(21), Array(22), Array(23), Array(24), Array(25), Array(26), Array(27), Array(28), Array(29))

但是,通常有许多方法可以更好地做到这一点,这可能会帮助您避免此错误和其他错误。

在Scala中,人们普遍认为,作为一种习语,不可变结构比可变结构更受欢迎。鉴于此,我建议您构造一个函数,使用不可变的方法将序列前缀添加到行中。有很多方法可以做到这一点,但最基本的方法是折叠操作。如果您不熟悉它,折叠可以被认为是结构上的转换,比如for循环的功能版本。

考虑到这一点,下面是如何获取一些行,这些行是一个列表[List[String]],并为所有行添加一个数字前缀。

def addPrefix(lls: List[List[String]]): List[List[String]] =
  lls.foldLeft((1, List.empty[List[String]])){
    // You don't need to annotate the types here, I just did that for clarity.
    case ((serial: Int, acc: List[List[String]]), value: List[String]) =>
      (serial + 1, (serial.toString +: value) +: acc)
  }._2.reverse

一个foldLeft建立的列表与我们想要的相反,这就是为什么我称之为。在结尾处反转。这是因为堆栈在遍历结构时如何工作,这超出了这个问题的范围,但是有很多关于为什么使用foldLeftfoldRight的好文章。

从我上面读到的内容来看,这就是示例中的行。

val columnOne: List[String] =
  List('1','2','3','4').map(_.toString)
val columnTwo: List[String] =
  List("A","abhc","agch","mknk")
val columnThree: List[String] =
  List("B", "gjgbn", "fgbhjf", "dfjf")

val rows: List[List[String]] =
  columnOne.zip(columnTwo.zip(columnThree)).foldLeft(List.empty[List[String]]){
    case (acc, (a, (b, c))) => List(a, b, c) +: acc
  }.reverse

这就产生了这个。

scala> rows.foreach(println)
List(1, A, B)
List(2, abhc, gjgbn)
List(3, agch, fgbhjf)
List(4, mknk, dfjf)

让我们尝试用它作为输入调用我们的函数。

scala> addPrefix(rows).foreach(println)
List(1, 1, A, B)
List(2, 2, abhc, gjgbn)
List(3, 3, agch, fgbhjf)
List(4, 4, mknk, dfjf)

好的,看起来不错。

现在来编写CSV文件。因为CSVWriter适用于Java集合类型,所以我们需要将我们的Scala类型转换为Java集合。在Scala中,您应该在最后一刻这样做。这样做的原因是Scala的类型旨在与Scala很好地配合使用,我们不想过早失去这种能力。在不变性方面,它们也比并行Java类型更安全(如果您使用的是不可变变体,本示例就是这样)。

让我们定义一个函数writeCsvFile,它获取文件名、标题行和行列表并将其写出。同样,有很多方法可以正确做到这一点,但这里有一个简单的例子。

def writeCsvFile(
  fileName: String,
  header: List[String],
  rows: List[List[String]]
): Try[Unit] =
  Try(new CSVWriter(new BufferedWriter(new FileWriter(fileName)))).flatMap((csvWriter: CSVWriter) =>
    Try{
      csvWriter.writeAll(
        (header +: rows).map(_.toArray).asJava
      )
      csvWriter.close()
    } match {
      case f @ Failure(_) =>
        // Always return the original failure.  In production code we might
        // define a new exception which wraps both exceptions in the case
        // they both fail, but that is omitted here.
        Try(csvWriter.close()).recoverWith{
          case _ => f
        }
      case success =>
        success
    }
  )

让我们把它分解一下。我使用的是scala.util包中的try数据类型。它类似于语言级别的try/catch/last块,但不是使用特殊构造来捕获异常,而是使用正常值。这是Scala中的另一个常见习语,更喜欢普通语言值而不是特殊语言控制流构造。

让我们仔细看看这个表达式(标题:行)。地图(toArray)。asJava。这个小表达式正在执行许多操作。首先,我们将标题行添加到行列表的前面(标题:行)。然后,由于CSVWriter想要一个Iterable

函数的其余部分非常简单。我们把行写出来,然后检查是否有故障。如果有,我们确保仍然尝试关闭CSVWriter

我在这里包含了一个完整的编译示例。

import com.opencsv._
import java.io._
import scala.collection.JavaConverters._
import scala.util._

object Main {

  val header: List[String] =
    List("Serial Number", "Record Type", "First File value", "Second file value")

  val columnOne: List[String] =
    List('1','2','3','4').map(_.toString)
  val columnTwo: List[String] =
    List("A","abhc","agch","mknk")
  val columnThree: List[String] =
    List("B", "gjgbn", "fgbhjf", "dfjf")

  val rows: List[List[String]] =
    columnOne.zip(columnTwo.zip(columnThree)).foldLeft(List.empty[List[String]]){
      case (acc, (a, (b, c))) => List(a, b, c) +: acc
    }.reverse

  def addPrefix(lls: List[List[String]]): List[List[String]] =
    lls.foldLeft((1, List.empty[List[String]])){
      case ((serial: Int, acc: List[List[String]]), value: List[String]) =>
        (serial + 1, (serial.toString +: value) +: acc)
    }._2.reverse

  def writeCsvFile(
    fileName: String,
    header: List[String],
    rows: List[List[String]]
  ): Try[Unit] =
    Try(new CSVWriter(new BufferedWriter(new FileWriter(fileName)))).flatMap((csvWriter: CSVWriter) =>
      Try{
        csvWriter.writeAll(
          (header +: rows).map(_.toArray).asJava
        )
        csvWriter.close()
      } match {
        case f @ Failure(_) =>
          // Always return the original failure.  In production code we might
          // define a new exception which wraps both exceptions in the case
          // they both fail, but that is omitted here.
          Try(csvWriter.close()).recoverWith{
            case _ => f
          }
        case success =>
          success
      }
    )

  def main(args: Array[String]): Unit = {
    println(writeCsvFile("/tmp/test.csv", header, addPrefix(rows)))
  }
}

这是运行该程序后文件的内容。

"Serial Number","Record Type","First File value","Second file value"
"1","1","A","B"
"2","2","abhc","gjgbn"
"3","3","agch","fgbhjf"
"4","4","mknk","dfjf"

我在原始帖子的评论中注意到您正在使用"au.com.bytecode"%"opencsv"%"2.4"。一般来说,我不熟悉opencsv库,但根据Maven Central的说法,这似乎是主存储库的一个非常古老的分支。我建议您使用主存储库。https://search.maven.org/search?q=opencsv

人们经常担心,当使用不变的数据结构和技术时,我们需要进行性能权衡。情况可能是这样,但通常渐近复杂性不变。上面的解决方案是O(n),其中n是行数。它有一个比可变解更高的常数,但通常这并不重要。如果是的话,可以采用一些技术,比如addPrefix中更显式的递归来缓解这种情况。然而,除非你真的需要,否则你永远不应该这样优化,因为这样会使代码更容易出错,更不惯用(因此可读性也更低)。

 类似资料:
  • 问题内容: 我正在尝试将数据整理到.CSV文件中。我想将数据放在特定的行中,所以我尝试将“ \ n”放进去,但是它不起作用。请帮助我将数据放入特定的行中。谢谢提前.. 问题答案: 您的代码看起来不错,并且我确定换行符已正确写入文件中。我能想到的唯一原因是,您使用的编辑器未将文件视为行分隔符,而是将对视为行分隔符(如Windows上的记事本)打开了文件。 因此,您可以使用编写换行符,也可以使用诸如的

  • 问题内容: 我有一个脚本(使用PhantomJS),用于测试加载网页需要多长时间。我要弄清楚的是如何写将页面加载到.csv文件所花费的时间结果。然后,如果我要重新运行测试,以将另一个结果添加到.csv文件中。 码: 问题答案: 您可以将fs模块与附加模式下的方法一起使用。 其中,文件路径是字符串,是包含CSV行的字符串。 就像是:

  • 我使用supercsv CsvBeanWriter将值写入csv文件。 示例类: 我得到的结果是: 注意

  • 问题内容: 我认为我应该完成一项我似乎无法解决的非常简单的任务。 如何将Python字典写入csv文件?我想要的只是将字典键写入文件的第一行,并将键值写入第二行。 我最接近的是以下内容(我是从别人的帖子中获得的): 问题是,上面的代码似乎只将密钥写入第一行,仅此而已。我没有将值写入第二行。 有任何想法吗? 问题答案: 您使用的是期望字典列表而不是字典的列表。您只想DictWriter.writer

  • 问题内容: 我想打开一个新的文本文件,然后将numpy数组保存到该文件。我写了这段代码: 我收到此错误: 有人知道怎么了吗? 另外,我在终端中找到了一个名为file_2的空文件,但是里面没有任何内容。 编辑:我正在使用Python3.4 问题答案: 看来您正在使用Python3。因此,请以二进制模式()而非文本模式()打开文件: 另外,关闭文件句柄,以确保将所有内容都写入磁盘。您可以使用-stat

  • 问题内容: 我正在努力寻找一种 将数据写入 Node.js中 的CSV 的方法。 有几个CSV插件可用,但是它们只能“写”到stdout。 理想情况下,我想使用循环 逐行 编写。 问题答案: 对于文档()具体状态,它可以用流(见使用,)。因此,使用stdout并不是硬编码。 当您出现其他一些CSV解析器时,您可能也想看看它们。