记一次使用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. java8 Optional 类

    package jdk180reduce; import java.util.ArrayList; import java.util.HashMap; import java.util.List; i ...

  2. yum本地源创建

    1 安装yum-utils包,yum-utils可以将需要的包下载在本地,安装后可以使用yumdownloader   yum -y install yum-utils* 2 建立目录/yum/yum ...

  3. CSS选择器使用

    今天要对CSS选择器的使用方法做一个全面的总结(几乎全部是从这篇文章摘抄的 https://blog.csdn.net/qq_39241986/article/details/82185697) CS ...

  4. MFC线程(二):线程同步临界区CRITICAL SECTION

    当多个线程同时使用相同的资源时,由于是并发执行,不能保证先后顺序.所以假如时一个公共变量被几个线程同时使用会造成该变量值的混乱. 下面来举个简单例子. 假如有一个字符数组变量 char g_charA ...

  5. 如何使用PL/SQL工具批量导出表、存储过程、序列

    PLSQL作为Oracle数据库进行操作常用工具,可以很方便的对表以及数据进行处理.工作中如果遇到数据库转移,需要将老数据库中的建表.建序列和存储过程语句导出,然后导入到新的数据库中这样序列号会自动, ...

  6. vue与react对比总结(一)

    一.react和vue设计上的共同理念 1.使用 Virtual DOM 2.提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件. 3.将注意力集中保持在核心库,而将其 ...

  7. 1年转行资深前端工程师,开源项目过 1k stars,完整学习过程

    先介绍下大致情况时间线. 18 年 8 月正式转方向为前端,之前做了一段时间的 iOS,后来因为对前端更感兴趣所以就打算转方向了.19 年 10 月入职当前公司,定级资深前端,分配到业务架构小组,自此 ...

  8. python基础知识-1

    1.python是静态的还是动态的?是强类型还弱类型? python是强类型的动态脚本语言: 强类型:不允许不同类型相加 动态:不使用显示类型声明,且确定一个变量的类型是在第一次给它赋值的时候 脚本语 ...

  9. 曹工说面试:当应用依赖jar包的A版本,中间件jar包依赖B版本,两个版本不兼容,这还怎么玩?

    背景 大一点的公司,可能有一些组,专门做中间件的:假设,某中间件小组,给你提供了一个jar包,你需要集成到你的应用里.假设,它依赖了一个日期类,版本是v1:我们应用也依赖了同名的一个日期类,版本是v2 ...

  10. Java基础笔记01-02-03-04

    一.今日内容介绍 1.Java开发环境搭建 2.HelloWorld案例 3.注释.关键字.标识符 4.数据(数据类型.常量) 01java语言概述 * A: java语言概述 * a: Java是s ...