CsvReader和CsvWriter操作csv文件
使用方法:
- 提供把实例数据输出到磁盘csv文件的功能
- 提供读取csv文件,并封装成指定实例的功能
- 小工具自己依赖了slf4j+logbak,以及fastJson,如果与系统冲突,可以在pom文件中去除
- 可以自己手动封装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方法,思路大致是:
- a. 获取Field的类型全称
- b. 根据全称,使用Class.forName()获取对应的Class实例
- c. 根据反射,获取valueOf方法
- 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文件的更多相关文章
- 用javacsv API 来操作csv文件
javacsv是国外开发的一个比较好的操作csv文件的API,这里简单讲一下用法. 先下载javacsv2.0.zip的文件,解压后,把javacsv.jar 添加到项目中. 本站下载地址: htt ...
- java操作csv文件之javacsv.jar应用
csv文件是分隔文件,如果使用java的io流来写,比较麻烦,这里为大家提供一个javacsv的jar包,这个很方便操作csv文件. 下载地址:https://pan.baidu.com/s/1i46 ...
- java 操作 csv文件
CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件中,数据“栏”以逗号分隔,可允许程序通 ...
- C#操作.csv文件Demo
1.使用OleDB操作.csv文件,比较费时 public static DataTable GetDataTableFromCsv(string path,bool isFirstRowHeader ...
- python中操作csv文件
python中操作csv文件 读取csv improt csv f = csv.reader(open("文件路径","r")) for i in f: pri ...
- Java操作csv文件
以前就一直很想搞懂一个问题就是java如何读取和写入csv文件,现在要花时间总结一波. 主要使用的javaCSV.jar javaCSV API:http://javacsv.sourceforge. ...
- springbatch操作CSV文件
一.需求分析 使用Spring Batch对CSV文件进行读写操作: 读取一个含有四个字段的CSV文件(id, name, age, score), 对文件做简单的处理, 然后输出到还有一个csv文件 ...
- Python操作csv文件
1.什么是csv文件 The so-called CSV (Comma Separated Values) format is the most common import and export fo ...
- 数学建模之Python操作csv文件
1.用Python通过csv文件里面的某一列,形成键值,然后统计键在其他列出现的次数. import pandas as pd import numpy as np import csv import ...
随机推荐
- WebForm下的$.ajax中contentType: “application/json” 的用法
不使用contentType: “application/json”则data可以是对象 $.ajax({ url: actionurl, type: "POST", datTyp ...
- [AHOI2009]飞行棋
嘟嘟嘟 刚开始想这道题的时候确实很蒙,只想到矩形对边做对应的弧长相等,然后想办法凑出相等的弧长.其实正解很简单,不要去想边,应该想对角线,因为根据初中园的知识,这个矩形的对角线是圆的直径,而直径所对的 ...
- nodejs实现mysql数据库的简单例子
在MySQLWorkbench中创建table存储用户的tokenId信息: use token; SET FOREIGN_KEY_CHECKS = ; DROP TABLE IF EXISTS `a ...
- print输出
python中的print输出可以用逗号"," >>> a = 1 >>> b = 2 >>> print a,b 1 2 逗 ...
- 更改backend
keras默认的backend是tensorflow,更改成theano方法如下: vim ~/.keras/keras.json { "image_dim_ordering":& ...
- 存储类、链接和内存管理(c prime plus)
首先介绍三个概念: (1)作用域:作用域描述了程序中可以访问一个标识符的一个或多个区域. 一共有三种作用域:代码块作用域.函数原型作用域和文件作用域 a.代码块作用域:一个代码块是包含在开始花括号和对 ...
- 【转】WCF设置拦截器捕捉到request和reply消息
原文:https://www.cnblogs.com/yanglang/p/7063743.html 我们需要拦截消息,并把消息打印出来,那么我们就需要一个拦截器,叫做MessageInspector ...
- 复制文件到IDE等工具出现乱码解决方案
首要的解决方案是设置文件或者项目或者工作空间的编码,可以采用在文件上.项目上右键->properties进行设置 第二种方式是在editplus等编辑器里打开文件,然后打开文件之后点击菜单Fil ...
- 消息队列ZeroMQ
消息队列概念 消息队列技术是分布式应用间交换信息的一种技术.消息队列可以驻留在内存或者磁盘上,队列存储消息直到它们被应用程序读走.通过消息队列,应用程序可以独立的执行,它们不需要知道彼此的位置,或者在 ...
- [ONTAK2010]Peaks kruskal重构树,主席树
[ONTAK2010]Peaks kruskal重构树练手题. LG传送门竟然不强制在线?看到离线水过很不爽:B站强制在线版传送门 看到"询问从点\(v\)开始只经过困难值小于等于\(x\) ...