zoukankan      html  css  js  c++  java
  • CsvReader和CsvWriter操作csv文件

    使用方法:

    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;
        }
    }
    

      

  • 相关阅读:
    AGC037F Counting of Subarrays
    AGC025F Addition and Andition
    CF506C Mr. Kitayuta vs. Bamboos
    AGC032D Rotation Sort
    ARC101F Robots and Exits
    AGC032E Modulo Pairing
    CF559E Gerald and Path
    CF685C Optimal Point
    聊聊Mysql索引和redis跳表
    什么是线程安全
  • 原文地址:https://www.cnblogs.com/donfaquir/p/10179353.html
Copyright © 2011-2022 走看看