记一次使用opencsv解析csv文件时碰到的坑

最近在开发过程中需要解析csv文件,公司用的解析工具是opencsv,在根据opencsv的官方文档去解析时发现csv文件中含有繁体字,使用其自带的CsvToBean来转换会出现异常com.opencsv.exceptions.CsvRequiredFieldEmptyException: Number of data fields does not match number of headers.于是我这里想到的方法是使用CsvReader来读取文件,然后通过反射来注入到bean中,这里做个记录希望对大家有帮助

一、引入依赖包

<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.4</version>
</dependency>

二、具体代码

1.自定义注解,基础一点的就是只需要定义数据列标题名title、格式转换convert,我这里是由于业务需要所以稍微复杂些

import java.lang.annotation.*;

/**
* <p>
* 解析csv文件注解
* </p>
*
* @Author zlc0w01
* @Date 2020/4/20 10:15
* @Version 1.0
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CsvReadColmn {
/**
* 该列数据的标题名
*/
String title(); /**
* 是否需要加密
*/
boolean encrypt() default false; /**
* 读csv文件字段绑定
* 绑定格式转换类,字符串转Object
* @return
*/
Class<? extends AbstractConvertCsvBase> convert() default AbstractConvertCsvBase.Converter.class; /**
* 转换依赖字段,如有某个字段转换需要依赖其他字段,
* 可设置为依赖字段的title
* @return
*/
String convertRelyColumn() default ""; }

2.接下来就是定义用于转换的基类了,这里面可以自己定义,我这里定义的意思是转换所有字段,去掉前面的单引号“'”,其他需要定义的转换规则可以继承这个类,然后重写convert方法就行了

public abstract class AbstractConvertCsvBase {
private static final String SPLIT = "'"; /**
* 转换
* @param params 参数中必须有key为"value"
* @return
*/
public Object startConvert(Map<String,String> params){
String value = params.get("value");
if (StringUtils.isNotBlank(value) && SPLIT.equals(value.substring(0,1))){
value = value.substring(1);
}
if (StringUtils.isBlank(value)){
return null;
}
params.put("value",value);
return convert(params);
} /**
* 转换方法
* @param params
* @return
*/
public abstract Object convert(Map<String,String> params); public static class Converter extends AbstractConvertCsvBase{
public static Converter newInstance() {
return new Converter();
}
@Override
public Object convert(Map<String,String> params) {
return params.get("value");
}
}
}

3.定义需要转换的bean

public class GbInsurancePolicy implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
* id
*/
@CsvReadColmn(title = "内部号码")
private String id; @CsvReadColmn(title = "出生日期",convert = CsvConvertStringToSimpleDate.class)
private Date birthday; } //上面说到定义转换规则,这里拿出生日期举例
public class CsvConvertStringToSimpleDate extends AbstractConvertCsvBase {

   @SneakyThrows
@Override
public Object convert(Map<String, String> params) {
String value = params.get("value");
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
return sf.parse(value);
}
}

4.定义反射来解析csv文件

public List<T> readSpecialCsv(String filePath) throws Exception{
List<T> list = new ArrayList<>();
FileInputStream fr = new FileInputStream(filePath);
UnicodeInputStream unicodeInputStream = new UnicodeInputStream(fr, true);
String enc = unicodeInputStream.getEncodingFromStream();
InputStreamReader is = new InputStreamReader(unicodeInputStream, enc);
CSVReader reader = new CSVReader(is);
String [] nextLine;
String[] header = reader.readNext();
while ((nextLine = reader.readNext()) != null) {
if (nextLine.length < header.length){
continue;
}
T t = getTClass().newInstance();
Field[] fields = t.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Field fieldName = t.getClass().getDeclaredField(field.getName());
CsvReadColmn csvReadColmn = fieldName.getAnnotation(CsvReadColmn.class);
if (null != csvReadColmn){
int columnPosition = Arrays.asList(header).indexOf(csvReadColmn.title());
String value = nextLine[columnPosition];
AbstractConvertCsvBase convert = csvReadColmn.convert().newInstance();
Map<String,String> params = new HashMap<>();
params.put("value",value);
//是否有需要依赖某个字段来转换的
if (StringUtils.isNotBlank(csvReadColmn.convertRelyColumn())){
int relyColumnPosition = Arrays.asList(header).indexOf(csvReadColmn.convertRelyColumn());
String relyColumn = nextLine[relyColumnPosition];
params.put("relyColumn",relyColumn);
}
Object obj = convert.startConvert(params);
String methodName = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method m = t.getClass().getDeclaredMethod(methodName, fieldName.getType());
m.invoke(t, obj);
}
}
list.add(t);
}
reader.close();
return list;
}

以上就是整个流程,希望对大家有帮助

java opencsv解析csv文件的更多相关文章

  1. php解析.csv文件

    public function actionImport() { //post请求过来的 $fileName = $_FILES['file']['name']; $fileTmpName = $_F ...

  2. JAVA简便解析json文件

    JAVA简便解析json文件 首先放上我要解析的json文件: { "resultcode":"200", "reason":"S ...

  3. [cocos2dx utils] cocos2dx读取,解析csv文件

    在我们的游戏中,经常需要将策划的数值配置成csv文件,所以解析csv文件就是一个很common的logic, 例如如下csv文件: 下面是一个基于cocos2dx 2.2.4的实现类: #ifndef ...

  4. Qt解析CSV文件

    最近需要解析Excel文件,于是顺带写了解析CSV的代码 定义数据类型LX::Sheet #ifndef LX_H #define LX_H #include <QString> #inc ...

  5. .NET 上传并解析CSV文件存库

    1.前端: 放置浏览按钮 <div class="row inner_table text-center"> <input id="fileId&quo ...

  6. Java jdom解析xml文件带冒号的属性

    Java jdom解析xml文件带冒号的属性 转载请标明出处: https://dujinyang.blog.csdn.net/article/details/99644824 本文出自:[奥特曼超人 ...

  7. 如何用Java解析CSV文件

    首先看一下csv文件的规则: csv(Comma Separate Values)文件即逗号分隔符文件,它是一种文本文件,可以直接以文本打开,以逗号分隔.windows默认用excel打开.它的格式包 ...

  8. 解析 csv文件 java ***最爱那水货

    /** * csv文件解析 <br> * wx 微信明细数据 第1行是标题 ,最后2行 是总结 提取数据需要过滤<br> * zfb 支付宝明细数据 前4行 和最后4行是总结 ...

  9. selenium3 文件系列之------ opencsv读取csv文件

    最近在学习selenium有关文件的读取测试,今天先总结一下如何读取csv文件.CSV的定义是与逗号分隔的值(Comma-Separated Values),在Java中需要用到第三方lib去处理读取 ...

随机推荐

  1. skywalking中文文档

    https://github.com/apache/skywalking/blob/v5.0.0-alpha/docs/README_ZH.md 大家可以前往如下地址下载我们的发布包: l  Apac ...

  2. centos下面基本的linux命令操作

    参考视频: 1.如何打开命令窗口 鼠标点击右键,选择open Terminal就可以打开命令行窗口了. 现在我们可以调整这个窗口的大小,增大窗口大小使用ctrl+shif+加号,缩小窗口ctrl+减号 ...

  3. 蝙蝠算法(BA)学习笔记

    算法原理 蝙蝠能够在夜间或十分昏暗的环境中自由飞翔和准确无误地捕捉食物,是因为他们能够从喉头发出地超声脉冲回声来定位.受这一启发,Yang教授在2010年提出了蝙蝠算法(Bat Algorithm,B ...

  4. 如何查看class文件的jdk版本

    版权声明:本文为博主原创文章,转载请注明本文链接.文章内容如有错误望能指正,以免误导更多人. https://blog.csdn.net/gnail_oug/article/details/47145 ...

  5. BigDecimal类型比较数字大小

    BigDecimal类型比较数字大小1.转成intBigDecimal b1 = new BigDecimal("-121454125453.145");if(b1.intValu ...

  6. BZOJ 3573米特运输

    Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市为 ...

  7. 六.url配置

    1.Django 如何处理一个请求 (1). django 加载 ROOT_URLCONF(settings.py中配置的) 指定的模块,并寻找可用的urlpatterns变量.它是 django.c ...

  8. html转义字符大全_网页html特殊符号,特殊字符查看对照表(整理)

    在HTML中,某些字符是预留的.比如不能使用小于号(<)和大于号(>),这是因为浏览器会误认为它们是标签.如果希望正确地显示预留字符,我们必须在 HTML 源代码中使用字符实体HTML中一 ...

  9. HDU 2236 无题II 题解

    题目 这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小. 输入格式 输入一个整数\(T\)表示\(T\)组数据. 对于每组数 ...

  10. Scrapy模拟登录赶集网

    1.打开赶集网登录界面,先模拟登录并抓包,获得post请求的request参数 2. 我们只需构造出上面的参数传入formdata即可 参数分析: setcookie:为自动登录所传的值,不勾选时默认 ...