在读取csv文件时无法移动到下一行

nic*_*ick 11 java csv scala

我有一个类帮助我读取csv文件,另一个类创建csv的每一行的对象,所以我可以分别为每一行运行一些操作.用它来实现自动化.

由于某种原因我的程序在一行之后停止了...之前有效,所以我不知道出了什么问题.

这是我的csv阅读器类:

import java.io.File
import com.github.tototoshi.csv.CSVReader
import jxl.{Cell, Workbook}

import scala.collection.mutable

trait DataSource {

  def read (fileName: String): Seq[Map[String, String]]
}

object CsvDataSource extends DataSource {
  import com.github.tototoshi.csv.CSVFormat
  import com.github.tototoshi.csv.Quoting
  import com.github.tototoshi.csv.QUOTE_MINIMAL

  implicit object MyFormat extends CSVFormat {
    val delimiter: Char = '\t'
    val quoteChar: Char = '"'
    val escapeChar: Char = '"'
    val lineTerminator: String = "\r\n"
    val quoting: Quoting = QUOTE_MINIMAL
    val treatEmptyLineAsNil: Boolean = false
  }

  override def read(file: String): Seq[Map[String, String]] = {
    val reader = CSVReader.open(file, "UTF-16")(MyFormat)
    reader.iteratorWithHeaders.toSeq
  }
}
Run Code Online (Sandbox Code Playgroud)

这是PurchaseInfo类,它创建csv的每一行的对象:

case class PurchaseInfo(
                         something1: String,
                         something2: String,
                         something3: String,
                         something4: String) {
}


object PurchaseInfo {

    private def changeDateFormat(dateInString: String): String = {
    //System.out.println(dateInString)
    val formatter: SimpleDateFormat = new SimpleDateFormat("MMM dd, yyyy")
    val formatter2: SimpleDateFormat = new SimpleDateFormat("dd/MM/yyyy")
    val date: Date = formatter.parse(dateInString)
    return formatter2.format(date).toString
  }

    def fromDataSource (ds: DataSource)(fileName: String): Seq[PurchaseInfo] = {

      ds.read(fileName).map { c =>
        PurchaseInfo(
          something1 = c("Supplier Address Street Number"),
          something2 = c("Supplier Address Route"),
          something3 = c("Supplier Address Locality"),
          something4 = c("Supplier Address Postal Code")
        )
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在我执行所有操作的类中,有一个名为insertData的方法获取一系列purchaseInfos,并在此seq中调用每个purchaseInfo的另一个方法....

def insertData (purchaseInfos: Seq[PurchaseInfo]) = {

    //logging in and then getting directed to the right path (where we start the invoices automation)
    login()

    val res = purchaseInfos.map { case purchaseInfo =>
      println(purchaseInfo.invoiceNumber)
      (purchaseInfo, Try(addInvoiceFlow(purchaseInfo)))
    }
    res
  }
Run Code Online (Sandbox Code Playgroud)

问题是insertData调用addInvoiceFlow只有一个与第一个purchaseInfo并停止...为什么?我检查了34行,所以没有csv文件的概率..

这是用scala编写的,但java也可以帮助:)

som*_*ytt 6

你有一系列的Stream.map.第一个iterator.toSeqtoStream.

iteratorWithHeaders.toSeq map PurchaseInfo.apply map addInvoiceFlow
Run Code Online (Sandbox Code Playgroud)

insertData不会急切地评估调用addInvoiceFlow,而只是头部元素.

scala> (1 to 10).toStream map { i => println(s"Hi, $i") ; i + 1}
Hi, 1
res0: scala.collection.immutable.Stream[Int] = Stream(2, ?)
Run Code Online (Sandbox Code Playgroud)

所以insertData返回这个部分评估的流.

你可以强制评估:

scala> res0.force
Hi, 2
Hi, 3
Hi, 4
Hi, 5
Hi, 6
Hi, 7
Hi, 8
Hi, 9
Hi, 10
res1: scala.collection.immutable.Stream[Int] = Stream(2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
Run Code Online (Sandbox Code Playgroud)

如果您有解析错误,也会出现此问题.看到这个评论.


Tim*_*Tim 4

我怀疑您在读完输入文件之前以某种方式关闭了它。我无法确定,因为您没有提供调用的代码insertDataread为了测试这个假设,尝试通过改变方法来实现文件的内容

reader.iteratorWithHeaders.toSeq
Run Code Online (Sandbox Code Playgroud)

reader.iteratorWithHeaders.toList
Run Code Online (Sandbox Code Playgroud)

如果此后它可以工作,则意味着您CSVReader在使用数据之前关闭了它。


更新:在我原来的答案中,我对修复的看法是正确的,但在我的解释中却不正确。正如 @som-snytt 在他的回答中正确指出的那样,它Stream.map没有实现流,它只是定义了在实际实现流时应该进行的附加元素转换。因此,在某些情况下,不在读取点实现流(从而创建Map随身携带的中间 s)可能会很有用,而是在 map 之后实现,此时实现将直接给你PurchaseInfos,即

ds.read(fileName).map { c => PurchaseInfo(...)}.force
Run Code Online (Sandbox Code Playgroud)