栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

使用CsvBeanReader读取具有可变列数的CSV文件

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用CsvBeanReader读取具有可变列数的CSV文件

编辑: 更新超级CSV
2.0.0-β-1

请注意,API已在Super CSV
2.0.0-beta-1中更改(代码示例基于1.52)。现在

getCSVHeader()
,所有读者都
getHeader()
可以使用该方法(与
writeHeader
作者一致)。

此外,

SuperCSVException
已重命名为
SuperCsvException


编辑: Super CSV 2.1.0更新

从2.1.0版开始,可以使用新方法 读取一行CSV 之后
执行单元处理器

executeProcessors()
。有关更多信息,请参见项目网站上的此示例。请注意,这仅与有关
CsvListReader
,因为它是唯一允许可变列长的读取器。


您是正确的-

CsvBeanReader
不支持列数可变的CSV文件。根据大多数CSV规范(包括RFC
4180),每行的列数必须相同。

因此,(作为超级CSV开发人员)我不愿意将此功能添加到超级CSV中。如果您想出一种优雅的添加方式,请随时在项目的SourceForge网站上提出建议。这可能意味着要扩展一个新的阅读器

CsvBeanReader
:它将不得不将读取和映射/处理分为两个单独的方法(除非您知道有多少列,否则您无法对bean的字段进行任何处理或映射)

简单的解决方案

解决此问题的简单方法(如果您可以控制要使用的CSV文件)是在编写CSV文件时简单地添加一个空白列(示例中的第一行的末尾带有逗号-
表示最后一列为空)。这样,您的CSV文件将是有效的(每行具有相同的列数),并且您可以

CsvBeanReader
按照自己的方式使用。

如果那不可能,那么 一切就不会丢失

花式的解决方案

您可能已经意识到,

CsvBeanReader
使用名称映射将CSV文件中的每一列与bean中的一个字段相关联,并使用CellProcessor数组来处理每一列。换句话说,如果要使用它,您必须知道有多少列(及其代表什么)。

CsvListReader
另一方面,它非常原始,可以读取不同长度的行(因为它不需要处理或映射它们)。

因此,您可以通过同时使用两个阅读器读取文件来组合

CsvBeanReader
with的所有功能
CsvListReader
(如以下示例中所述):
CsvListReader
用于找出有多少列,并
CsvBeanReader
进行处理/映射。

请注意,这是假设仅可能不存在birthDate列(即,如果您无法确定缺少哪一列,它将不起作用)。

package example;import java.io.StringReader;import java.util.Date;import org.supercsv.cellprocessor.ParseDate;import org.supercsv.cellprocessor.ift.CellProcessor;import org.supercsv.exception.SuperCSVException;import org.supercsv.io.CsvBeanReader;import org.supercsv.io.CsvListReader;import org.supercsv.io.ICsvBeanReader;import org.supercsv.io.ICsvListReader;import org.supercsv.prefs.CsvPreference;public class VariableColumns {    private static final String INPUT = "name,birthDate,cityn"        + "John,New Yorkn"         + "Sally,22/03/1974,Londonn"         + "Jim,Sydney";    // cell processors    private static final CellProcessor[] NORMAL_PROCESSORS =     new CellProcessor[] {null, new ParseDate("dd/MM/yyyy"), null };    private static final CellProcessor[] NO_BIRTHDATE_PROCESSORS =     new CellProcessor[] {null, null };    // name mappings    private static final String[] NORMAL_HEADER =     new String[] { "name", "birthDate", "city" };    private static final String[] NO_BIRTHDATE_HEADER =     new String[] { "name", "city" };    public static void main(String[] args) {        // using bean reader and list reader together (to read the same file)        final ICsvBeanReader beanReader = new CsvBeanReader(new StringReader(     INPUT), CsvPreference.STANDARD_PREFERENCE);        final ICsvListReader listReader = new CsvListReader(new StringReader(     INPUT), CsvPreference.STANDARD_PREFERENCE);        try { // skip over header beanReader.getCSVHeader(true); listReader.getCSVHeader(true); while (listReader.read() != null) {     final String[] nameMapping;     final CellProcessor[] processors;     if (listReader.length() == NORMAL_HEADER.length) {         // all columns present - use normal header/processors         nameMapping = NORMAL_HEADER;         processors = NORMAL_PROCESSORS;     } else if (listReader.length() == NO_BIRTHDATE_HEADER.length) {         // one less column - birth date must be missing         nameMapping = NO_BIRTHDATE_HEADER;         processors = NO_BIRTHDATE_PROCESSORS;     } else {         throw new SuperCSVException(      "unexpected number of columns: "   + listReader.length());     }     // can now use CsvBeanReader safely      // (we know how many columns there are)     Person person = beanReader.read(Person.class, nameMapping,  processors);     System.out.println(String.format(  "Person: name=%s, birthDate=%s, city=%s",  person.getName(), person.getBirthDate(),  person.getCity())); }        } catch (Exception e) { // handle exceptions here e.printStackTrace();        } finally { // close readers here        }    }    public static class Person {        private String name;        private Date birthDate;        private String city;        public String getName() { return name;        }        public void setName(String name) { this.name = name;        }        public Date getBirthDate() { return birthDate;        }        public void setBirthDate(Date birthDate) { this.birthDate = birthDate;        }        public String getCity() { return city;        }        public void setCity(String city) { this.city = city;        }    }}

我希望这有帮助。

哦,您的

Entry
类中的字段为何不遵循正常的命名约定(camelCase)有什么理由吗?如果将
header
阵列更新为使用camelcase,则字段也可以是camelcase。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/452876.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号