使用方法:

  1. 提供把实例数据输出到磁盘csv文件的功能
  2. 提供读取csv文件,并封装成指定实例的功能
  3. 小工具自己依赖了slf4j+logbak,以及fastJson,如果与系统冲突,可以在pom文件中去除
  4. 可以自己手动封装jar包,引入到自己的工程,也可以复制CsvUtils.java和CsvConfig.java到工程,直接使用

踩的坑:

反射:

使用反射,创建新实例并给各个属性赋值,获取属性值后,调用set方法赋值,因为获取的值都是String类型,需要根据属性值类型对值转型。

  • 一开始希望写一个转类型方法,根据传入的Field的类型,把String类型的值转成属性值,构造的方法类似:
private <T> T tranform(Field field, String value){
switch(field.getType().getSimpleName()){
case "String":
...
return (T)xxx;
case ...
}
}

但是出现一个问题,没法转换,一直提示无法把String转换成Object.后来放弃了

  • 打算使用反射的方式,使用基础类型的封装类型中的valueOf方法,思路大致是:
  1. a. 获取Field的类型全称
  2. b. 根据全称,使用Class.forName()获取对应的Class实例
  3. c. 根据反射,获取valueOf方法
  4. d. 执行valueOf方法,把String类型的值转成Field的Type

代码大致是,手打的,不是真正的代码:

String typeName = field.getType.getName();
Class<?> typeClass = Class.forName(typeName);
Method valueOf = typeClass.getDeclearMethod("valueOf",java.lang.String);
Object obj = typeClass.newInstence(); //这一步出错
valueof.invoke(obj,value); //把要赋予属性的值,由String类型转换成属性类型

但是在获取封装类型的实例是,也就是 Object obj = typeClass.newInstence(); 这一步,提示,无法获取Integer类型的实例,提示是的没有`<init>`什么的,抛出异常的位置是 C:/Program Files/Java/jdk1.8.0_101/src.zip!/java/lang/Class.java:3082 。后来琢磨了一会,发现只有String类型有无参构造方法,其他封装类型都没有无参构造方法,不知道是不是这个原因,String类型可以通过反射获取实例,其他封装类型不能获取实例。

最后放弃挣扎,使用枚举,使用封装类型的valueOf方法对值进行转换。实现方式后面代码。

1、工具实现代码

package com.donfaquir.csv;

import com.csvreader.CsvReader;
import com.csvreader.CsvWriter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*; /**
* @author:
* @description: 提供csv文件的操作方法
* @date Create in 2018/12/24 15:01
* @modified By:
*/
public class CsvUtil { private final Logger log = LoggerFactory.getLogger(CsvUtil.class); /**
* 读取csc文件
*
* @param filePath 文件路径
* @param clazz 指定类型
* @param csvConfig 配置信息
* @return 读取结果
*/ public <T> List<T> readFile(String filePath, Class<T> clazz, CsvConfig csvConfig) throws Exception {
if (null == filePath || null == clazz) {
return null;
}
List<T> result = new ArrayList<>(10);
this.checkCsvConfig(csvConfig);
CsvReader reader = new CsvReader(filePath, csvConfig.getSeparator(), Charset.forName(csvConfig.getCharset())); //获取类方法
Map<Field, Method> methods = new HashMap<>(11);
Field[] fields = clazz.getDeclaredFields();
if (fields == null) {
log.error("========未获取到类{}的属性值,请确认类{}是否传入正确========", clazz.getName(), clazz.getName());
return null;
}
for (int i = 0; i < fields.length; i++) {
String methodName = "set" + fields[i].getName().substring(0, 1).toUpperCase() + fields[i].getName().substring(1);
Method method = clazz.getMethod(methodName, fields[i].getType());
if (method == null) {
log.info("====类{}中没有属性{}的set方法,请确定是否实现====", clazz.getName(), fields[i].getName());
continue;
}
methods.put(fields[i], method);
}
//跳过头文件
reader.readHeaders();
String[] headers = reader.getHeaders();
if(null == headers || headers.length <=0){
log.error("========文件< {} >缺少数据头,请增加数据头到文件========",filePath);
return null;
}
while (reader.readRecord()) {
T obj = (T)clazz.newInstance();
Set<Field> keys = methods.keySet();
for (Field key : keys) {
key.setAccessible(true);
String value = reader.get(key.getName());
if(StringUtils.isBlank(value)){
continue;
}
switch (key.getType().getSimpleName()) {
case "Integer":
methods.get(key).invoke(obj,Integer.valueOf(value));
break;
case "String":
methods.get(key).invoke(obj,value);
break;
case "Boolean":
methods.get(key).invoke(obj,Boolean.valueOf(value));
break;
case "Long":
methods.get(key).invoke(obj,Long.valueOf(value));
break;
case "Float":
methods.get(key).invoke(obj,Float.valueOf(value));
break;
case "Double":
methods.get(key).invoke(obj,Double.valueOf(value));
break;
case "Date":
try {
methods.get(key).invoke(obj,new SimpleDateFormat(csvConfig.getDateFormat()).parse(value));
break;
} catch (ParseException e) {
log.info("====日期转换失败,使用的日期格式为:{},与给定的日期数据格式不匹配,请重新指定日期转换格式====",csvConfig.getDateFormat());
log.info("====错误原因:{}",e);
throw new RuntimeException(e);
}
default:
methods.get(key).invoke(obj,value);
break;
}
}
result.add(obj);
}
reader.close();
return result;
} /**
* 读取csc文件
* 默认编码格式是本地编码格式
* @param filePath 文件路径
* @param separator 分隔符
* @param t 指定类型
* @return 读取结果
*/
public <T> List<T> readFile(String filePath, char separator, Class<T> t) throws Exception {
return this.readFile(filePath,t,this.initCsvConfig());
} /**
* 把缓存内容写入到csv文件
*
* @param filePath 文件路径
* @param cacheContainer 缓存容器
* @param csvConfig 配置信息
* @return 写入是否成功
*/
public <T> boolean writeFile(String filePath, List<T> cacheContainer, Class<T> t,CsvConfig csvConfig) {
CsvWriter writer;
if (StringUtils.isBlank(filePath) || CollectionUtils.isEmpty(cacheContainer) || null == t) {
return false;
}
this.checkCsvConfig(csvConfig);
writer = new CsvWriter(filePath, csvConfig.getSeparator(), Charset.forName(csvConfig.getCharset()));
//获取实体类中的属性
Field[] fields = t.getDeclaredFields();
//生成数据头
String[] headers = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
headers[i] = fields[i].getName();
}
//写入到文件
try {
writer.writeRecord(headers);
for (T obj : cacheContainer) {
String[] str = coverFieldsValue(obj,csvConfig);
writer.writeRecord(str);
}
} catch (Exception e) {
e.printStackTrace();
}
writer.close();
return true;
} /**
* 把缓存内容写入到csv文件
* 默认编码格式是本地编码格式
* @param filePath 文件路径
* @param cacheContainer 缓存容器
* @return 写入是否成功
*/
public <T> boolean writeFile(String filePath, List<T> cacheContainer, Class<T> t) {
return this.writeFile(filePath,cacheContainer,t,this.initCsvConfig());
} /**
* 把传入的实例属性的值封装成字符串数组
*
* @param obj 实例
* @return 字符串数组
* @throws Exception 异常
*/
private <T> String[] coverFieldsValue(T obj,CsvConfig csvConfig) throws Exception {
String[] result ;
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
if (null == fields || fields.length <= 0) {
return null;
}
result = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
new Date();
String methodName = "get" + fields[i].getName().substring(0, 1).toUpperCase() + fields[i].getName().substring(1);
Method method = clazz.getMethod(methodName);
Object value = method.invoke(obj);
if(null == value){
continue;
}
if("Date".equals(fields[i].getType().getSimpleName())){
Date date = (Date)value;
result[i] = new SimpleDateFormat(csvConfig.getDateFormat()).format(date);
continue;
}
result[i] = value.toString();
}
return result;
} /**
* 构造一个默认的配置实例
* 默认编码格式为本地系统编码格式
* @return 设有默认值的配置实例
*/
private CsvConfig initCsvConfig(){
String charset = System.getProperty("file.encoding");
return new CsvConfig(charset,"yyyy-MM-dd HH:mm:ss:SSS",',');
} /**
* 检测给予系统配置信息的完整性
* @param csvConfig 给定的配置实例
*/
private void checkCsvConfig(CsvConfig csvConfig){
if(null == csvConfig){
csvConfig = initCsvConfig();
}else{
if(null == csvConfig.getCharset()){
csvConfig.setCharset(System.getProperty("file.encoding"));
}
if(null == csvConfig.getDateFormat()){
csvConfig.setDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
}
//没有指定分隔符
if(0 == csvConfig.getSeparator()){
csvConfig.setSeparator(',');
}
}
}
}

  

2、参数实体类

用于指定编码类型、日期格式和分隔符

package com.donfaquir.csv;

/**
* @author:
* @description: 工具配置类
* @date Create in 2018/12/26 10:09
* @modified By:
*/
public class CsvConfig { /** 字符编码 */
private String charset;
/** 日期格式 */
private String dateFormat;
/** 分隔符 */
private char separator; public CsvConfig(){ }
public CsvConfig(String charset, String dateFormat, char separator){
this.charset = charset;
this.dateFormat = dateFormat;
this.separator = separator;
} public String getCharset() {
return charset;
} public void setCharset(String charset) {
this.charset = charset;
} public String getDateFormat() {
return dateFormat;
} public void setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
} public char getSeparator() {
return separator;
} public void setSeparator(char separator) {
this.separator = separator;
}
}

  

3、使用demo

import bean.User;
import com.donfaquir.csv.CsvConfig;
import com.donfaquir.csv.CsvUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.List; /**
* @author:
* @description: 测试类
* @date Create in 2018/12/24 15:22
* @modified By:
*/
public class Demo {
private static Logger log = LoggerFactory.getLogger(Demo.class); public static void main(String[] args){
String filePath = System.getProperty("user.home")+"/csv_test.csv";
CsvConfig csvConfig = new CsvConfig("gbk","yyyy-MM-dd HH:mm:ss:SSS",',');
CsvUtil csvUtil = new CsvUtil(); //写文件代码
/* User user = new User("李磊", "男", 14, new Date(), true, 133443L);
User user1 = new User("jack", "M", 22, new Date(), false, 134L);
ArrayList<User> users = new ArrayList<>(3);
users.add(user);
users.add(user1);
csvUtil.writeFile(filePath, users, User.class,csvConfig);*/ //读文件代码
try {
List<User> objects = csvUtil.readFile(filePath, User.class,csvConfig);
if(CollectionUtils.isEmpty(objects)){
log.info("====没有从文件{}获取到值====",filePath);
}
log.debug("==获取的结果总数:{}",objects.size());
// log.debug("==获取的结果:{}", JSON.toJSONString(objects));
} catch (Exception e) {
e.printStackTrace();
} }
}

  

4、使用中用到的domain类

package bean;

import java.util.Date;

/**
* @author:
* @description: 用户类
* @date Create in 2018/12/24 15:21
* @modified By:
*/
public class User {
/** 用户名 */
private String name;
/** 性别 */
private String sex;
/** 年龄 */
private Integer age;
/** 生日 */
private Date birthday;
/** 信息是否公开 */
private Boolean visible;
/** 过车整形id */
private Long longId; public User() {
super();
} public User(String name, String sex, Integer age, Date birthday, Boolean visible, Long longId) {
this.name = name;
this.sex = sex;
this.age = age;
this.birthday = birthday;
this.visible = visible;
this.longId = longId;
} public Date getBirthday() {
return birthday;
} public void setBirthday(Date birthday) {
this.birthday = birthday;
} public Boolean getVisible() {
return visible;
} public void setVisible(Boolean visible) {
this.visible = visible;
} public Long getLongId() {
return longId;
} public void setLongId(Long longId) {
this.longId = longId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}

  

CsvReader和CsvWriter操作csv文件的更多相关文章

  1. 用javacsv API 来操作csv文件

    javacsv是国外开发的一个比较好的操作csv文件的API,这里简单讲一下用法. 先下载javacsv2.0.zip的文件,解压后,把javacsv.jar 添加到项目中.  本站下载地址: htt ...

  2. java操作csv文件之javacsv.jar应用

    csv文件是分隔文件,如果使用java的io流来写,比较麻烦,这里为大家提供一个javacsv的jar包,这个很方便操作csv文件. 下载地址:https://pan.baidu.com/s/1i46 ...

  3. java 操作 csv文件

    CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件中,数据“栏”以逗号分隔,可允许程序通 ...

  4. C#操作.csv文件Demo

    1.使用OleDB操作.csv文件,比较费时 public static DataTable GetDataTableFromCsv(string path,bool isFirstRowHeader ...

  5. python中操作csv文件

    python中操作csv文件 读取csv improt csv f = csv.reader(open("文件路径","r")) for i in f: pri ...

  6. Java操作csv文件

    以前就一直很想搞懂一个问题就是java如何读取和写入csv文件,现在要花时间总结一波. 主要使用的javaCSV.jar javaCSV API:http://javacsv.sourceforge. ...

  7. springbatch操作CSV文件

    一.需求分析 使用Spring Batch对CSV文件进行读写操作: 读取一个含有四个字段的CSV文件(id, name, age, score), 对文件做简单的处理, 然后输出到还有一个csv文件 ...

  8. Python操作csv文件

    1.什么是csv文件 The so-called CSV (Comma Separated Values) format is the most common import and export fo ...

  9. 数学建模之Python操作csv文件

    1.用Python通过csv文件里面的某一列,形成键值,然后统计键在其他列出现的次数. import pandas as pd import numpy as np import csv import ...

随机推荐

  1. linux下ab网站压力测试命令

    http://domain:代表压测域名.   get方法压测:        1)一般get方法压测简单,直接后缀url就ok了,参数直接挂在url后面的?a=1&b=2,         ...

  2. node.js学习之post文件上传 (multer中间件)

    express为了性能考虑,采用按需加载的方式,引入各种中间件来完成需求, 平时解析post上传的数据时,是用body-parser. 但这个中间件有缺点,只能解析post的文本内容,(applica ...

  3. sql server 2000 错误229 拒绝了对象sysobjects 的select 权限

    此问题是权限问题,我的解决办法是因为添加角色的时候勾选太多导致的 !!!!!!千万不要勾选db_denydatareader.

  4. Java反射学习四

    利用反射调用私有方法.访问私有属性 利用反射,首先是Class对象的获取,之后是Method和Field对象的获取. 以Method为例,从文档中可以看到: getMethod()方法返回的是publ ...

  5. ICC Scenario Definition

    现代先进工艺下的后端设计都是在 MCMM 情况下设计的,所谓 MCMM 就是 muti-corner  muti-mode,用于芯片的不同工作模式和工作条件. 后端设计过程中,需要保证芯片在所有工作模 ...

  6. HDU 2298(纯物理加解一元二次方程)

    Toxophily Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  7. bat设置windows计划任务

    设置定时任务 @echo off set NAME=dailybackup :: set DAY=MON,TUE,WED,THU,FRI,SAT,SUN set COMMAND=cscript.exe ...

  8. block本质探寻四之copy

    说明: <1>阅读本文,最好阅读之前的block文章加以理解: <2>本文内容:三种block类型的copy情况(MRC).是否深拷贝.错误copy: 一.MRC模式下,三种b ...

  9. javascript初学者注意事项

    注:以下属于个人学习中的理解不能保证全部正确,如果有错误以后修正. 1.javascript和c#语言一样严格区分大小写,有没有类的概念. 2.所有的变量声明都使用var,虽然能打出蓝色int,但却不 ...

  10. Scrapy-从数据库取出IP并判断是否可用

    import pymysql import requests conn = pymysql.connect(host="localhost",user="root&quo ...