使用方法:

  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. haproxy 启动错误

    在haproxy启动时会报错 ALERT] / () : Starting proxy short_message: cannot bind socket 问题1,如果bind的是vip,则需要内核添 ...

  2. etherlime-4-Etherlime CLI

    Etherlime CLI命令行界面 Installing & Help Syntax语法 npm i -g etherlime Install the global etherlime to ...

  3. python pyspark入门篇

    一.环境介绍: 1.安装jdk 7以上 2.python 2.7.11 3.IDE pycharm 4.package: spark-1.6.0-bin-hadoop2.6.tar.gz 二.Setu ...

  4. (转)一次压测对nginx/tomcat配置的调整

    原文地址:还在寻找.... 一个web系统,前端使用nginx做为反向代理,处理https,并将请求转发给后端的tomcat服务. 压力测试工具选择了jmeter. 首先简单介绍一下jmeter. 它 ...

  5. Kafka基础认识

    1):Apache kafka介绍及架构详解 假设一个场景: 数据源: 应用系统A 产生的用户访问数据和订单数据 10000 条一秒钟 push:推送数据 消息系统:队列 产生的数据量>数据量 ...

  6. uip.h 笔记

    想了解uip,可以从uip.h开始,他对主体函数有详细的说明,和案例 初始化 1 设定IP网络设定 2 初始化uip 3 处理接收包 4 ARP包处理 5 周期处理,tcp协议处理 uip_proce ...

  7. go 交叉编译,部署

    go web 部署 交叉编译 go 语言有个强大的地方就是 交叉编译 windows --cmd 设置环境变量-mac SET CGO_ENABLED=0 SET GOOS=darwin SET GO ...

  8. JQuery第二天——JQuery的DOM操作

    JQuery拥有隐式迭代和显式迭代 因为JQuery为类数组对象,可以使用手动遍历实现显式 .each():也可以使用 $("p").click(function(){ var t ...

  9. Android ListView demo

    创建一个空的 Activity 相对应的layout文件会自动创建: ?xml version="1.0" encoding="utf-8"?> < ...

  10. 2017战略No.1:坚定不移地走全产业链发展路线

    编者按:2016年9月9日,首次公开表达"我想走全产业链发展路线"的想法. 这几个月,认真思考了下这个决定背后的原因.目的和价值. 付出常人5倍以上的努力,先抓住"技术研 ...