2016-04-15 5 views
4

Ich habe eine CSV-Datei mit 37 Spalten, die ich in Java mit Apache Commons CSV 1.2 analysiere. Mein Setup-Code lautet wie folgt:Fehleranalyse aufgrund von CSV-Unterschieden vor/nach dem Speichern (Java mit Apache Commons CSV)

//initialize FileReader object 
FileReader fileReader = new FileReader(file); 

//intialize CSVFormat object 
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING); 

//initialize CSVParser object 
CSVParser csvFileParser = new CSVParser(fileReader, csvFileFormat); 

//Get a list of CSV file records 
List<CSVRecord> csvRecords = csvFileParser.getRecords(); 

// process accordingly 

Mein Problem ist, dass, wenn ich die CSV-Kopie an mein Zielverzeichnis zu verarbeiten und mein Parsing-Programm ausführen, ich die folgende Fehlermeldung erhalten:

Exception in thread "main" java.lang.IllegalArgumentException: Index for header 'Title' is 7 but CSVRecord only has 6 values! 
     at org.apache.commons.csv.CSVRecord.get(CSVRecord.java:110) 
     at launcher.QualysImport.createQualysRecords(Unknown Source) 
     at launcher.QualysImport.importQualysRecords(Unknown Source) 
     at launcher.Main.main(Unknown Source) 

jedoch Wenn ich die Datei in mein Zielverzeichnis kopiere, öffne und speichere sie, dann probiere das Programm erneut, es funktioniert. Das Öffnen und Speichern der CSV fügt die Kommas, die am Ende benötigt werden, zurück, so dass mein Programm nicht davon ausgehen kann, dass es nicht genug Header zum Lesen gibt.

Für Kontext, hier ist eine Probenleitung von vor/nach dem Speichern:

Vor (Fehlern): "Daten", "Daten", "Daten", "Daten"

Nach (in Betrieb) : "Daten", "Daten" ,,,, Daten ",,," Daten ",,,,,

Also meine Frage: Warum ändert sich das CSV-Format, wenn ich es öffne und es speichere? Ich ändere keine Werte oder Codierung, und das Verhalten ist beim MS-DOS oder regulären .csv-Format das gleiche. Außerdem verwende ich Excel zum Kopieren/Öffnen/Speichern in meinem Test.

Gibt es eine Codierung oder Formateinstellung, die ich verwenden muss? Kann ich das programmatisch lösen?

Vielen Dank im Voraus!

EDIT # 1:

Weitere Kontext, als ich zum ersten Mal eine leere Zeile in der ursprünglichen Datei anzuzeigen, hat es gerade die neue Linie^M Zeichen wie folgt aus:

^M 

Nach Öffnung in Excel und speichern, es sieht aus wie dies mit allen 37 meiner leeren Felder:

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,^M 

Ist dies eine Diskrepanz Windows-Kodierung?

Antwort

1

Vielleicht ist das ein Kompatibilitätsproblem mit dem, was die Datei an erster Stelle generiert hat. Es scheint, dass Excel eine leere Zeile als eine gültige Zeile mit leeren Zeichenfolgen in jeder Spalte mit der Anzahl der Spalten akzeptiert, die mit anderen Zeilen übereinstimmen. Dann speichert es es gemäß CSV-Konventionen mit dem Spaltenbegrenzer. (der^M das Carriage Return Zeichen, die auf Microsoft-Systemen die Zeilenvorschub-Zeichen am Ende einer Zeile in Textdateien voran)

Vielleicht können Sie mit ihm durch die Erstellung eigene Reader Unterklasse zwischen dem sitzen beschäftigen FileReader und der CSVParser. Ihr Leser liest eine Zeile und wenn sie leer ist, geben Sie eine Zeile mit der richtigen Anzahl an Kommas zurück. Ansonsten gib einfach die Zeile wie sie ist zurück.

Zum Beispiel:

class MyCSVCompatibilityReader extends BufferedReader 
    { 
    private final BufferedReader delegate; 

    public MyCSVCompatibilityReader(final FileReader fileReader) 
     { 
     this.delegate = new BufferedReader(fileReader); 
     } 

    @Override 
    public String readLine() 
     { 
     final String line = this.delegate.readLine(); 
     if ("".equals(line.trim()) 
      { return ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"; } 
     else 
      { return line; } 
     } 
    } 

viele andere Details sind korrekt zu implementieren, wenn die Schnittstelle zu implementieren. Sie müssen Anrufe an alle anderen Methoden weiterleiten (Schließen, Fertig, Zurücksetzen, Überspringen usw.) und sicherstellen, dass jede der verschiedenen Methoden ordnungsgemäß funktioniert. Es kann einfacher sein, wenn die Datei leicht in den Speicher passt, einfach die Datei lesen und die korrigierte Version in eine neue StringWriter schreiben und dann eine StringReader an den CSVParser erstellen.

+0

Toller Input, danke für die Zeit. Ich habe auch gerade gelesen, dass RFC 4180 der Standard ist, nach dem Excel eine "nicht konforme" CSV-Datei speichert, was wiederum der Grund dafür ist, dass ich die Kommas nach dem Speichern sehe. Ich werde versuchen, meinen eigenen Reader zu implementieren, weil ich ihn programmatisch lösen muss. – corneria

-1

Vielleicht versuchen Sie dies: Erstellt einen Parser für die angegebene Datei. analysieren (Datei Datei, Charset Zeichensatz, CSVFormat Format)

// importieren importieren java.nio.charset.StandardCharsets; //StandardCharsets.UTF_8

Hinweis: Diese Methode erzeugt eine intern Filereader verwendet FileReader.FileReader (java.io.File), die wiederum auf der Standard-Codierung der JVM beruht, der den Code ausführt.

+0

Was hat das mit dem Hinzufügen der fehlenden Spalten zu tun? – RealSkeptic

+0

vielleicht mitAllowMissingColumnNames? CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader (FILE_HEADER_MAPPING) .withAllowMissingColumnNames(); – user1176726

+1

Versuchen Sie nicht, zu raten. Wenn Sie die Sache erforscht haben und die Antwort kennen, dann antworten Sie. Aber nur ungeprüfte Vorschläge zu werfen ist nicht die Art, wie die Dinge auf Stack Overflow funktionieren. Außerdem sollten Sie Ihre Antwort formatieren, insbesondere die Teile, die Code sind. – RealSkeptic

-1

Oder vielleicht mitAllowMissingColumnNames versuchen?

//intialize CSVFormat object 
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING).withAllowMissingColumnNames(); 
+0

Nein, das würde folgern, dass die Spalte da ist, ohne einen Namen. Meine Spalten sind einfach nicht da (bevor ich die Datei speichere) – corneria