Подтвердить что ты не робот

Невозможно перейти на следующую строку при чтении файла csv

У меня есть класс, который помогает мне читать файл 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 VATBoxFormat 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")(VATBoxFormat)
    reader.iteratorWithHeaders.toSeq
  }
}

это класс 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")
        )
      }
    }
}

Теперь, в классе, где я выполняю все действия, есть один метод, называемый insertData, который получает последовательность buyInfos и вызывает другой метод с каждой покупкой Info внутри этого seq....

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
  }

проблема в том, что insertData вызывает addInvoiceFlow только один с первой покупкойInfo и останавливается... почему? Я проверил, и есть 34 строки, поэтому нет проблем с файлом csv.

это написано в scala, но java тоже может помочь:)

4b9b3361

Ответ 1

Я подозреваю, что вы как-то закрываете входной файл, прежде чем закончите читать его. Я не могу точно сказать, потому что вы не предоставляете код, который вызывает insertData. Чтобы проверить эту гипотезу, попробуйте материализовать содержимое вашего файла в методе read, изменив

reader.iteratorWithHeaders.toSeq

к

reader.iteratorWithHeaders.toList

Если он будет работать после этого, это означает, что вы закрываете CSVReader, прежде чем будете потреблять свои данные.


Обновление: в моем первоначальном ответе я был прав насчет исправления, но не прав в моих объяснениях. Как правильно заметил @som-snytt в своем ответе, Stream.map не реализует поток, он просто определяет дополнительное преобразование элемента, которое должно быть сделано, когда поток фактически реализуется. Поэтому в некоторых случаях может быть полезно не понимать поток в точке считывания (таким образом создавая промежуточный Map, который переносится вокруг), а скорее делать это после карты, когда реализация напрямую даст вам PurchaseInfo s, т.е.

ds.read(fileName).map { c => PurchaseInfo(...)}.force

Ответ 2

У вас есть серия Stream.map. Первый iterator.toSeq - это просто toStream.

iteratorWithHeaders.toSeq map PurchaseInfo.apply map addInvoiceFlow

insertData не будет с нетерпением оценивать вызовы addInvoiceFlow, а только элемент head.

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

Итак, 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)

Там также эта проблема, если у вас есть ошибка синтаксического анализа. См. этот комментарий.

Ответ 3

Проверьте, является ли терминатор линии последовательностью \r\n.

Он также может быть только \n.

Символ \r - это возврат каретки, а \n - символ новой строки. Windows использует пару \r\n для обратной совместимости с dos.

Unix использует только \n.