Usando o CsvBeanReader para ler um arquivo CSV com um número variável de colunas
Então, estou trabalhando na análise de um arquivo .csv. Tomei o conselho de outro segmento em algum lugar no StackOverflow e baixei o SuperCSV. Eu finalmente consegui praticamente tudo funcionando, mas agora encontrei um bug que parece difícil de consertar.
O problema ocorre porque as duas últimas colunas de dados podem ou não ser preenchidas. Aqui está um exemplo de um arquivo .csv com a primeira linha faltando a última coluna e a segunda linha totalmente concluída:
2012: 07: 25,11: 48: 20,922, "uLog.exe", "", Tecla pressionada, 1246,341, -1,00, -1,00,1.00, Deslocamento 2012: 07: 25,11: 48: 21,094, " uLog.exe "," ", Tecla pressionada, 1246,341, -1,00, -1,00,1.00, b, Shift
Da minha compreensão doSuper Javadoc CSV, não há como preencher um Java Bean com oCsvBeanReader se houver um número variável de colunas. Isso parece muito burro porque eu sinto que essas colunas ausentes devem ser permitidas como nulas ou outro valor padrão quando o Bean é inicializado.
Para referência, aqui está o meu código completo para o analisador:
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();
}
}
E o código da classe Entry:
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(){}
}
E a exceção que estou recebendo (note que esta é uma linha diferente do meu exemplo acima, perdendo as duas últimas colunas):
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)
Sim, escrever todos aqueles getters e setters era uma dor no rabo. Além disso, peço desculpas, eu provavelmente não tenho uma convenção perfeita no meu uso do SuperCSV (como o CellProcessor para usar se você quer apenas a String não modificada), mas você tem a idéia. Além disso, esse código obviamente não está completo. Por enquanto, estou apenas tentando recuperar com sucesso uma linha de dados.
Neste ponto, estou me perguntando se usar o CsvBeanReader é possível para meus propósitos. Se não, estou um pouco desapontado, já que o CsvListReader (eu colocaria o hyperlink, mas o StackOverflow não está me permitindo também, também é burro) é quase tão fácil quanto não usar a API, e apenas usar o Scanner.next ()
Qualquer ajuda seria apreciada. Desde já, obrigado!