如何使用Super CSV处理具有未知列数的CSV文件

4
对于一个项目,我需要处理CSV文件,但在运行时不知道列数。这些CSV文件是完全有效的,我只需要对几个不同的文件执行简单的任务。我需要分析列的值,因此需要使用用于处理CSV文件的库。为了简单起见,假设我需要做一些简单的事情,比如向所有文件追加日期列,无论它们有多少列。我想使用Super CSV来完成这个任务,因为我也在其他任务中使用这个库。
我遇到的问题更多的是概念性问题。如果我事先不知道有多少列,我不确定应该如何处理文件。如果我不知道文件中有哪些列以及有多少列,我不确定应该如何定义映射任意CSV文件的POJOs或如何定义Cell Processors。我如何动态创建与列数匹配的Cell processors?例如,我如何基于CSV文件的标题定义POJOs?
考虑这样一种情况:我有两个CSV文件:products.csv和address.csv。假设我想为这两个文件都添加一个带有今天日期的日期列,而不必编写两个不同的方法(例如addDateColumnToProduct()和addDateColumnToAddress()),它们执行相同的操作。

product.csv:

name, description, price
"Apple", "red apple from Italy","2.5€" 
"Orange", "orange from Spain","3€"

address.csv:

firstname, lastname
"John", "Doe"
"Coole", "Piet"

根据CSV文件的标题信息,我该如何定义一个映射产品CSV的POJO?同样的问题也适用于Cell Processors吗?我该如何定义一个非常简单的Cell Processor,它只有正确数量的构造函数参数,例如针对product.csv?

CellProcessor[] processor = new CellProcessor[] { 
    null,
    null,
    null
};

并且对于 address.csv 文件:

CellProcessor[] processor = new CellProcessor[] { 
    null,
    null
};

这是否可能?我是不是走错了路来实现这个目标?

编辑 1: 我不是在寻找一个能够处理单个文件中具有可变列的 CSV 文件的解决方案。我试图弄清楚在运行时是否可以处理任意 CSV 文件,即是否可以仅基于 CSV 文件中包含的标题信息创建 POJOs,在不知道 csv 文件将有多少列的情况下。

解决方案: 根据 @baba 的回答和评论

private static void readWithCsvListReader() throws Exception {

        ICsvListReader listReader = null;
        try {
                listReader = new CsvListReader(new FileReader(fileName), CsvPreference.TAB_PREFERENCE);

                listReader.getHeader(true); // skip the header (can't be used with CsvListReader)
                int amountOfColumns=listReader.length();
                CellProcessor[] processor = new CellProcessor[amountOfColumns];
                List<Object> customerList;

                while( (customerList = listReader.read(processor)) != null ) {
                        System.out.println(String.format("lineNo=%s, rowNo=%s, customerList=%s", listReader.getLineNumber(),
                                listReader.getRowNumber(), customerList));
                }

        }
        finally {
                if( listReader != null ) {
                        listReader.close();
                }
        }
}
2个回答

3
也许有点晚了,但这可能会有所帮助...
  CellProcessor[] processors=new CellProcessor[properties.size()];

  for(int i=0; i< properties.zise(); i++){
            processors[i]=new Optional();

   }
    return  processors;

for(int i=0; i< properties.size(); i++){..你的回答中有一个拼写错误,看起来可以满足要求。 - Sid

1

这是一个非常常见的问题,互联网上有多个与此相关的教程,包括 Super Csv 页面:

http://supercsv.sourceforge.net/examples_reading_variable_cols.html

如此一行所述:

如下所示,您可以在调用read()后通过调用executeProcessors()方法执行单元格处理器。因为它是在读取CSV行之后完成的,所以您有机会检查有多少列(使用listReader.length()),并提供正确数量的处理器。


似乎他们所说的“可变列”实际上是指“可选列”。看起来你需要为每个可能的列数提供一个处理器才能使其工作。 - kapex
你可以通过解析头部来观察列数,然后智能决定使用的处理器数量。 - Nikola Yovchev
感谢@baba,我编辑了我的问题以使其更加精确。我知道我可以解析标题并计算列数,但是在运行时如何创建具有动态参数数量(例如每个列一个“null”参数)的新CellProcessor对象? - Stefan
此外,您可以使用 openCSV 而不是 SuperCSV。只需放弃整个“面向对象方法出了点问题”的想法并开始将每一行作为字符串列表处理即可。 - Nikola Yovchev
@MightyApe确实需要使用一些解析逻辑,但您可以只解析列数,获取其长度,然后执行:CellProcessor[] processor = new CellProcessor[suchLength]; - Nikola Yovchev
@baba,我基于你的解决方案添加了一个小代码片段。有时候人们看不到显而易见的东西。感谢你的帮助。 - Stefan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接