Verwenden von CsvBeanReader zum Lesen einer CSV-Datei mit einer variablen Anzahl von Spalten
Also arbeite ich daran, eine CSV-Datei zu analysieren. Ich habe den Rat eines anderen Threads irgendwo auf StackOverflow genommen und SuperCSV heruntergeladen. Ich habe endlich so ziemlich alles zum Laufen gebracht, aber jetzt bin ich auf einen Fehler gestoßen, der schwierig zu beheben scheint.
Das Problem tritt auf, weil die letzten beiden Datenspalten möglicherweise nicht ausgefüllt sind. Hier ist ein Beispiel für eine CSV-Datei, bei der in der ersten Zeile die letzte Spalte fehlt und die zweite Zeile vollständig ist:
2012: 07: 25,11: 48: 20,922, "uLog.exe", "", Tastendruck, 1246,341, -1,00, -1,00,1,00, Schicht 2012: 07: 25,11: 48: 21,094, " uLog.exe "," ", Taste gedrückt, 1246,341, -1,00, -1,00,1,00, b, Umschalt
Aus meinem Verständnis derSuper CSV Javadocgibt es keine Möglichkeit, eine Java Bean mit demCsvBeanReader wenn es eine variable Anzahl von Spalten gibt. Dies scheint wirklich dumm zu sein, da ich der Meinung bin, dass diese fehlenden Spalten bei der Initialisierung des Beans null oder ein anderer Standardwert sein sollten.
Als Referenz ist hier mein vollständiger Code für den Parser:
public class ULogParser {
String uLogFileLocation;
String screenRecorderFileLocation;
private static final CellProcessor[] cellProcessor = new CellProcessor[] {
new ParseDate("yyyy:MM:dd"),
new ParseDate("HH:mm:ss"),
new ParseDate("SSS"),
new StrMinMax(0, 100),
new StrMinMax(0, 100),
new StrMinMax(0, 100),
new ParseInt(),
new ParseInt(),
new ParseDouble(),
new ParseDouble(),
new ParseDouble(),
new StrMinMax(0, 100),
new StrMinMax(0, 100),
};
public String[] header = {"Date", "Time", "Msec", "Application", "Window", "Message", "X", "Y", "RelDist", "TotalDist", "Rate", "Extra1", "Extra2"};
public ULogParser(String uLogFileLocation, String screenRecorderFileLocation)
{
this.uLogFileLocation = uLogFileLocation;
this.screenRecorderFileLocation = screenRecorderFileLocation;
}
public void parse()
{
try {
ICsvBeanReader reader = new CsvBeanReader(new BufferedReader(new FileReader(uLogFileLocation)), CsvPreference.STANDARD_PREFERENCE);
reader.getCSVHeader(false); //parse past the header
Entry entry;
entry = reader.read(Entry.class, header, cellProcessor);
System.out.println(entry.Application);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void sendToDB()
{
Query query = new Query();
}
}
Und der Code für die Entry-Klasse:
public class Entry
{
private Date Date;
private Date Time;
private Date Msec;
private String Application;
private String Window;
private String Message;
private int X;
private int Y;
private double RelDist;
private double TotalDist;
private double Rate;
private String Extra1;
private String Extra2;
public Date getDate() { return Date; }
public Date getTime() { return Time; }
public Date getMsec() { return Msec; }
public String getApplication() { return Application; }
public String getWindow() { return Window; }
public String getMessage() { return Message; }
public int getX() { return X; }
public int getY() { return Y; }
public double getRelDist() { return RelDist; }
public double getTotalDist() { return TotalDist; }
public double getRate() { return Rate; }
public String getExtra1() { return Extra1; }
public String getExtra2() { return Extra2; }
public void setDate(Date Date) { this.Date = Date; }
public void setTime(Date Time) { this.Time = Time; }
public void setMsec(Date Msec) { this.Msec = Msec; }
public void setApplication(String Application) { this.Application = Application; }
public void setWindow(String Window) { this.Window = Window; }
public void setMessage(String Message) { this.Message = Message; }
public void setX(int X) { this.X = X; }
public void setY(int Y) { this.Y = Y; }
public void setRelDist(double RelDist) { this.RelDist = RelDist; }
public void setTotalDist(double TotalDist) { this.TotalDist = TotalDist; }
public void setRate(double Rate) { this.Rate = Rate; }
public void setExtra1(String Extra1) { this.Extra1 = Extra1; }
public void setExtra2(String Extra2) { this.Extra2 = Extra2; }
public Entry(){}
}
Und die Ausnahme, die ich erhalte (beachten Sie, dass dies eine andere Zeile als in meinem obigen Beispiel ist und die beiden letzten Spalten fehlen):
Exception in thread "main" The value array (size 12) must match the processors array (size 13): You are probably reading a CSV line with a different number of columns than the number of cellprocessors specified context: Line: 2 Column: 0 Raw line: [2012:07:25, 11:48:05, 740, uLog.exe, , Logging started, -1, -1, -1.00, -1.00, -1.00, ] offending processor: null at org.supercsv.util.Util.processStringList(Unknown Source) at org.supercsv.io.CsvBeanReader.read(Unknown Source) at processing.ULogParser.parse(ULogParser.java:59) at ui.ParseImplicitData.main(ParseImplicitData.java:15)
Ja, all diese Getter und Setter zu schreiben war ein Schmerz im Arsch. Ich entschuldige mich auch dafür, dass ich bei der Verwendung von SuperCSV (wie dem, was CellProcessor verwenden soll, wenn Sie nur den nicht modifizierten String wollen) wahrscheinlich keine perfekte Konvention habe, aber Sie haben die Idee. Auch dieser Code ist offensichtlich nicht vollständig. Im Moment versuche ich nur, eine Datenzeile erfolgreich abzurufen.
An dieser Stelle frage ich mich, ob die Verwendung des CsvBeanReader für meine Zwecke möglich ist. Wenn nicht, bin ich ein wenig enttäuscht, da der CsvListReader (ich würde einen Hyperlink posten, aber StackOverflow erlaubt es mir nicht, auch dumm) so einfach ist, als würde man die API überhaupt nicht verwenden und nur Scanner.next verwenden ().
Jede Hilfe wäre dankbar. Danke im Voraus!