2011-11-27 43 views
2

@Carlo V. Dango 我简化了我的问题,并且我已经阅读了文档 - 建议不要惊慌。不过,我有问题。帮我解决一个问题,它会解决所有问题。谢谢。解析SuperCSV字符串

问题:当我有一个缺少非字符串字段的csv记录时,如何(甚至是否可以)将缺少的条目转换为默认值,或者至少不会抛出NullPointerException?可选的cellProcessor也不会阻止错误。

这个程序基本上来自SuperCSV网站。

package com.test.csv; 
import java.io.FileReader; 

import org.supercsv.cellprocessor.ParseBigDecimal; 
import org.supercsv.cellprocessor.ParseDate; 
import org.supercsv.cellprocessor.ParseInt; 
import org.supercsv.cellprocessor.ift.CellProcessor; 
import org.supercsv.io.CsvBeanReader; 
import org.supercsv.io.ICsvBeanReader; 
import org.supercsv.prefs.CsvPreference; 


public class CSVReader { 

private static final CellProcessor[] cellProcessor = new CellProcessor[] { 
    null, 
    null, 
    new ParseInt(), 
    new ParseDate("yyyyMMdd"),  
    new ParseBigDecimal()  
}; 

public static void main (String[] args) throws Exception { 

    CsvPreference pref = new CsvPreference('"', '|', "\n"); 

    ICsvBeanReader inFile = new CsvBeanReader(new FileReader("C:\\temp\\sapfilePipe.txt"), pref); 
    try { 
     final String[] header = inFile.getCSVHeader(true); 
     User user; 
     while ((user = inFile.read(User.class, header, cellProcessor)) != null) { 
      System.out.println(user); 
     } 
    } finally { 
     inFile.close(); 
    } 

} 

}

这里是CSV文件,我读。注意第一条记录中有一个缺失的字段(年龄)。

firstName|lastName|age|hireDate|hourlyRate 
A.|Smith| |20110101|15.50 

我的用户豆:

package com.test.csv; 

import java.math.BigDecimal; 
import java.util.Date; 

public class User { 

private String firstName; 
private String lastName; 
private int age; 
private Date hireDate; 
private BigDecimal hourlyRate; 
    ...getters/setters... 

以下是错误:

Exception in thread "main" java.lang.NullPointerException 
    at org.supercsv.io.CsvBeanReader.fillObject(Unknown Source) 
    at org.supercsv.io.CsvBeanReader.read(Unknown Source) 
    at com.glazers.csv.CSVReader.main(CSVReader.java:31) 

感谢。

回答

1

列表阅读器将每行读入字符串列表。看来这是你正在寻找的。

http://supercsv.sourceforge.net/javadoc/org/supercsv/io/CsvListReader.html

或这里http://supercsv.sourceforge.net/codeExamples_general.html所示,你可以设置处理器为空,如果你不希望任何具体的实现。

+0

非常感谢您... – Davidson

+0

嗨...如果我有一个应该转换为BigDecimal的空白列,我试图\t \t \t \t \t新ParseBigDecimal(新StrReplace(””,‘0’)), – Davidson

+0

当建立cellprocessors,你从内到外或在外面搭建....例如..如果我有一个空白在一列,否则将是一个数量值,我如何链处理器将空白转换为0,然后使用ParseBigDecimal?我越来越绝望地理解我不理解的东西。意识到我可以在CellProcessor数组中放置一个空值是巨大的。我在网站的例子中解释为“阅读但未处理”,完全忽略。 – Davidson

3

编辑:更新Super CSV 2.0.0-beta-1

超级CSV 2.0.0-β-1是现在出来。它包含许多错误修复和新功能(包括Maven支持和用于映射嵌套属性和数组/集合的新Dozer扩展)。

它也改变了空("")列的处理方式 - 它们现在被读为null。 这意味着您的bean中的firstNamelastName字段现在将是null而不是""(如果它们不存在于CSV文件中)。

Optional()处理器已更新为迎合此 - 它仍然会以相同的方式运行。

我使用Token的建议是不再相关:你应该使用ConvertNullTo代替:

new ConvertNullTo(-1, new ParseInt()) 

真的想什么Optional CellProcessor,这将只允许在下一处理器如果列不为空,则执行链。

所以更新CellProcessor数组:

private static final CellProcessor[] cellProcessor = new CellProcessor[] { 
    null, 
    null, 
    new Optional(new ParseInt()), 
    new ParseDate("yyyyMMdd"),  
    new ParseBigDecimal()  
}; 

这样,ParseInt只会得到,如果列不是空执行(CellProcessors从左至右执行),留下与bean的INT领域的默认值为0.

如果要将字段设置为-1以表示未提供任何值,则可以使用Token处理器,该处理器将用期望值替换任何标记(在本例中为“”)值,对于任何其他输入,它将继续到下一个处理器。即

new Token("", -1, new ParseInt()) 

@Carlo五男子的CsvListReader是一个非常原始的实现(和你失去映射到豆的能力),所以我只用它来快速和肮脏的解析。

而且我只建议在数组中使用null(读取时)获取不需要进一步处理的字符串属性。

顺便说一句,我在为即将发布的超级CSV项目工作。我一定会在网页上改进代码示例;)

+0

非常感谢您提供这个建议。在我原来的问题的实例中,我走了制作bean中所有字段字符串的路线,并在我的过程中稍后解析它们。我将采用这个示例,并使用我必须使用的输入文件对它进行测试。我一直认为我的问题是我自己在链接单元处理器方面的笨拙。我爱豆阅读器/作家。我们公司正在转型为SAP,它有许多读/写所有定制界面的CSV文件的机会。 SuperCSV是我们现在处理中的重要参与者。 – Davidson

+1

@Davidson很高兴听到您仍在使用Super CSV,这是一个非常棒的小API。它已经休眠了一段时间,但我最近加入了这个项目,希望能为它注入新的活力。如果您有任何关于新功能的问题或想法,请发布在Super CSV SourceForge论坛上 - 我们很乐意听取您的意见。你很幸运,你与SAP的接口是CSV,在我的工作中它是位置的(第一列是20个字符,第二个是10个字符等)!顺便说一下,如果你觉得这有帮助,你可以投票/选择这个答案? –