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

      

  • 相关阅读:
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
  • 原文地址:https://www.cnblogs.com/donfaquir/p/10179353.html
Copyright © 2011-2022 走看看