2

我正在使用 SuperCSV 将 CSV 记录解析为对象。我的 CSV 文件最后有额外的列,我只想处理前 X 列。所以我String[]为前 X 列定义CellProcessor[]了相同大小的映射。但它似乎不起作用并抛出异常,即单元处理器的数量应该与列数完全相同。

有人可以告诉我我是否遗漏了什么。即使我不想要它们,我是否需要将映射数组定义为具有与五个完全相同的列?

  public CsvToBeanParser(Reader reader, Class<T> type, CsvPreference preference, CellProcessor[] cellProcessors, String[] mapping, boolean skipHeader)
        throws IOException {
    this.beanReader = new CsvBeanReader(reader, preference);
    this.mapping = mapping;
    if (skipHeader) {
        beanReader.getHeader(true);
    }
    this.cellProcessors = cellProcessors;
    this.type = type;

}

/**
 * Parse and return record.
 * 
 * @return
 * @throws Exception
 *             if there is any parsing error
 */
public T getItem() throws Exception {
    try {
        return (T) beanReader.read(type, mapping, cellProcessors);
    } catch (Exception e) {
        LOG.error("Error parsing record", e);
        throw e;
    }
}

这是我的映射和单元处理器

String[] mapping = {"column1", "column2"};
CellProcessor[] cellProcessors = {null, null};

这适用于文件

column1, column2
1,2

但失败了(我想忽略 column3 )

column1, column2, column3
1,2,3
4

2 回答 2

5

如果您使用 CSV 文件的标题作为,nameMapping那么您将永远不需要知道有多少列,您只需使用它们。如果它们不适合映射(它们的名称与 bean 中的设置器不对应),那么您需要为自己nameMapping提供正确数量的元素。

如果您的 CSV 文件有一个标题,并且您知道您只需要前 2 列,那么您可以简单地提供一个与标题相同大小的 nameMapping 数组(以及可选的单元处理器数组),但只​​有前 2 个元素人口稠密。

String[] header = beanReader.getHeader(true);

// only interested in first 2 columns (rest set to null)
String[] nameMapping = 
    Arrays.copyOf(new String[]{"column1","column2"}, header.length);

// processors are optional, but you can populate these if you want
CellProcessor[] processors = new CellProcessor[header.length];

// TODO: read your CSV here...
于 2013-06-14T11:25:21.783 回答
0

如果您无权访问标头或解析非常大的文件,您可以执行以下操作:

只需扩展CsvBeanReader

public class FlexibleCsvBeanReader extends CsvBeanReader {

    public FlexibleCsvBeanReader(final Reader reader, final CsvPreference preferences) {
        super(reader, preferences);
    }

    @Override
    protected List<Object> executeProcessors(final List<Object> processedColumns, final CellProcessor[] processors) {
//      we have to make sure that processors.length is equal to columnSize (thats the real column-count of the csv)
        final int columnSize = getColumns().size();
//      resize the array
        final CellProcessor[] newProcessors = new CellProcessor[columnSize];
        System.arraycopy(processors, 0, newProcessors, 0, processors.length);
//      do default stuff
        return super.executeProcessors(processedColumns, newProcessors);
    }
}

只要新列仅在末尾,就可以忽略命名映射。如果您认为这是一种不好的做法,您也必须重写该read方法。

您还可以缓存调整大小的数组,因为根据您的处理器可能需要一些时间。CellProcessor但这仅在您为每一行应用相同的数组时才有意义。

于 2013-12-10T13:07:07.607 回答