如何使用supercsv跳过仅限空格的行和具有可变列的行

时间:2016-01-23 01:54:02

标签: java csv opencsv supercsv

我正在研究CSV解析器要求,我正在使用supercsv解析器库。我的CSV文件可以包含25列(由制表符(|)分隔)和最多100k行以及其他标题行。

我想忽略只有空格的行和包含少于25列的行。

我正在使用带有名称映射的IcvBeanReader(将csv值设置为pojo)和用于读取文件的字段处理器(用于处理验证)。

我假设Supercsv IcvBeanReader默认会跳过空白行。但如果一行包含少于25个列号,如何处理?

2 个答案:

答案 0 :(得分:1)

您可以通过编写自己的Tokenizer轻松完成此操作。

例如,以下Tokenizer将具有与默认Tokenizer相同的行为,但会跳过任何没有正确列数的行。

public class SkipBadColumnCountTokenizer extends Tokenizer {

    private final int expectedColumns;

    private final List<Integer> ignoredLines = new ArrayList<>();

    public SkipBadColumnCountTokenizer(Reader reader, 
            CsvPreference preferences, int expectedColumns) {
        super(reader, preferences);
        this.expectedColumns = expectedColumns;
    }

    @Override
    public boolean readColumns(List<String> columns) throws IOException {
        boolean moreInputExists;
        while ((moreInputExists = super.readColumns(columns)) && 
            columns.size() != this.expectedColumns){
            System.out.println(String.format("Ignoring line %s with %d columns: %s", getLineNumber(), columns.size(), getUntokenizedRow()));
            ignoredLines.add(getLineNumber());
        }

        return moreInputExists;

    }

    public List<Integer> getIgnoredLines(){
        return this.ignoredLines;
    }
}

使用此Tokenizer进行简单测试......

@Test
public void testInvalidRows() throws IOException {

    String input = "column1,column2,column3\n" +
            "has,three,columns\n" +
            "only,two\n" +
            "one\n" +
            "three,columns,again\n" +
            "one,too,many,columns";

    CsvPreference preference = CsvPreference.EXCEL_PREFERENCE;
    int expectedColumns = 3;
    SkipBadColumnCountTokenizer tokenizer = new SkipBadColumnCountTokenizer(
        new StringReader(input), preference, expectedColumns);

    try (ICsvBeanReader beanReader = new CsvBeanReader(tokenizer, preference)) {
        String[] header = beanReader.getHeader(true);
        TestBean bean;
        while ((bean = beanReader.read(TestBean.class, header)) != null){
            System.out.println(bean);
        }
        System.out.println(String.format("Ignored lines: %s", tokenizer.getIgnoredLines()));
    }

}

打印以下输出(注意它是如何跳过所有无效行的):

TestBean{column1='has', column2='three', column3='columns'}
Ignoring line 3 with 2 columns: only,two
Ignoring line 4 with 1 columns: one
TestBean{column1='three', column2='columns', column3='again'}
Ignoring line 6 with 4 columns: one,too,many,columns
Ignored lines: [3, 4, 6]

答案 1 :(得分:0)

(1)如果选择必须由Java程序使用Super CSV完成,那么(我引用)“你将不得不使用CsvListReader”。特别是:listReader.length()

有关详细信息,请参阅this Super CSV page

(2)如果您可以通过预处理CSV文件来执行选择,那么您可能希望考虑使用合适的命令行工具(或工具,具体取决于CSV格式的复杂程度)。如果CSV文件的分隔符不在任何字段中出现,那么awk就足够了。例如,如果满足假设,并且分隔符为|,则相关的awk过滤器可以如下所示:

awk -F'|' 'NF == 25 {print}'

如果CSV文件格式对于awk的天真应用而言过于复杂,那么您可能希望将复杂格式转换为更简单的格式;通常TSV有很多值得推荐的。