2015-09-07 15 views
11

Mam klasę, która pomaga mi odczytać plik CSV, i inną klasę, która tworzy obiekt dla każdej linii CSV, więc mogę uruchomić pewne akcje dla każdej linii osobno . używając tego do automatyzacji.Nie mogę przejść do następnej linii podczas odczytu pliku CSV

Z jakiegoś powodu po jednej linii zatrzymuje mój program ... to działało wcześniej, więc nie wiem co jest nie tak ..

to moja klasa czytelnik 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 
    } 
} 

to PurchaseInfo Klasa, która tworzy obiekt o każdej linii 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") 
     ) 
     } 
    } 
} 

teraz w klasie gdzie mogę wykonywać wszystkie czynności jest jedna metoda zwana insertData że dostać sekwencję kupna- haseInfos i wywołuje inny sposób z każdym purchaseInfo wewnątrz tego nast ....

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 
    } 

problemem jest to, że insertData wzywa addInvoiceFlow tylko jeden z pierwszym purchaseInfo i zatrzymuje ... dlaczego? Sprawdziłem i istnieje 34 linii, więc nie ma prob z pliku csv ..

ten jest napisany w języku Java Scala ale może pomóc też :)

+0

Nie pokazujesz, jak zbudowany jest argument 'purchaseInfos' z' insertData'. Czy jesteś pewien, że w tej sekwencji jest więcej niż jeden wpis? – Tim

Odpowiedz

4

Podejrzewam, że zamykasz plik wejściowy, zanim skończysz go czytać. Nie mogę powiedzieć na pewno, ponieważ nie podajesz kodu, który wywołuje insertData. Aby przetestować tę hipotezę próbować urzeczywistnić treść pliku w read metody zmieniając

reader.iteratorWithHeaders.toSeq 

do

reader.iteratorWithHeaders.toList 

czy to będzie działać po tym, oznacza to, że po zamknięciu CSVReader przed zużywać dane.


Aktualizacja: w mojej oryginalnej odpowiedzi miałem rację co do poprawki, ale nie w moim wyjaśnieniu. Jak słusznie zauważył @ som-snytt w swojej odpowiedzi, Stream.map nie realizuje strumienia, to jedynie definiuje dodatkową transformację elementu, która powinna zostać wykonana, gdy strumień jest faktycznie zrealizowany. Dlatego w niektórych przypadkach może być użyteczne, aby nie zrealizować strumienia w punkcie odczytu (w ten sposób tworząc pośrednie Map s, które są przenoszone), ale robimy to po mapie, kiedy realizacja da bezpośrednio PurchaseInfo s, tj.

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

Sprawdź, czy linia terminatora jest sekwencją \r\n. To może być tylko \n.

Znak \r to powrót karetki, natomiast \n jest znakiem nowej linii. Windows używa pary \r\n dla kompilacji wstecznej z dos.

Unix używać tylko \n.

+0

Próbowałem użyć \ n tylko teraz, to nie jest to:/ –

+0

Ogólnie, klasy Java IO do odczytu plików tekstowych nie przejmują się końcem linii. –

6

Masz serię Stream.map. Pierwsza wersja iterator.toSeq to tylko toStream.

iteratorWithHeaders.toSeq map PurchaseInfo.apply map addInvoiceFlow 

insertData nie będzie chętnie ocenić wywołania z addInvoiceFlow, ale tylko element głowicy.

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

Tak więc insertData zwraca ten częściowo wyceniony strumień.

Można wymusić ocenę:

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) 

Jest też this issue w przypadku gdy masz błąd składniowy. Zobacz this comment.

Powiązane problemy