个人使用19: opencsv应用

场景: 系统需要导出大数据文件。目标导出梳理在500w。

通常的excel,旧版大约是在63w-65w。 新版在100w左右。500w远超excel导出要求,所以决定采用csv文件进行处理。

原先导出csv文件通常是利用io流进行编写,本次学习使用opencsv来进行项目使用。

原先是因为有历史项目是参考opencsv实现,对应版本在4.0,属于较为早期项目,本次前期也是使用4.0进行了简单demo实现,但是发现有部分功能没办法很好实现。所以在网上也查找了很多资料,对应csdn、gitee、github都进行查阅。但是找到的版本都极为有限,没办法很好配合自己的需求。

后续决定投入时间进行知识储备学习,对应查阅到opencsv官网,对应版本已经升级到5.6,升级时间为2022.2.20,距离目前时间也很接近,而且还持续更新,下一个6.0的版本也值得期待。

学习之路:

1、查阅博客: 较好博客推荐

csv文件处理-opencsv 对应网址 https://www.jianshu.com/p/6414185b2f01

opencsv官网 对应网址 http://opencsv.sourceforge.net/#skipping_filtering_and_verifying

opencsv接口 对应网址 http://opencsv.sourceforge.net/apidocs/overview-summary.html

opencsv源码地址 对应地址 https://sourceforge.net/p/opencsv/source/ci/master/tree/

maven官网 https://mvnrepository.com/

对应maven下载jar地址 https://mvnrepository.com/artifact/com.opencsv/opencsv/5.6

对应接口文档 http://opencsv.sourceforge.net/xref-test/index.html

2、翻阅对应gitee项目跟github项目。 搜索关键词 opencsv / csv 自行搜索

3、搞项目 - 遇到问题解决问题

本次参考4.0模板 后续追加追加填充对应代码进行完善

util - CsvUtils.java

package com.fuhua.csvdemo.util;

import com.opencsv.CSVWriter;
import com.opencsv.bean.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.input.BOMInputStream;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
* opencsv 5.6 最新2022.2.20版本进行修正
* <br/>
* @author zhouyiwei
* @date 2022/3/24 16:26
*/
@Slf4j
public class CsvUtils {


    private static final String CSV = "csv";


    /**
    * 实体类写入CSV文件,全部一起写入。对应生成csv文件默认是UTF-8格式。
     * 推荐使用的bean数量 在1000行或者1000以内。
     *
     * withQuotechar(CSVWriter.DEFAULT_QUOTE_CHARACTER) ==> 默认bean对应数据不存在以""代替
     * withSeparator(CSVWriter.DEFAULT_SEPARATOR) ==> 对应csv文件以,拼接
     * withEscapechar('\\')  ==> 转义符设置
     *
     * Writer 为普通写入
     * CSVWriter 是opencsv特有写入
     *
    * <br/>
     * @param filePath	待生成的文件路径
     * @param tClass	bean对应实体类
     * @param writeList	具体的beanList 数据
    * @return [filePath, tClass, writeList]
    * @author zhouyiwei
    * @date 2022/3/26 10:05
    */
    public static  <T> void writeCsv(String filePath, Class<T> tClass, List<T> writeList) {
        Writer writer = null;
        try{
            writer = Files.newBufferedWriter(Paths.get(filePath));
            StatefulBeanToCsv<T> beanToCsv = new StatefulBeanToCsvBuilder<T>(writer)
                    .withQuotechar(CSVWriter.DEFAULT_QUOTE_CHARACTER)
                    .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                    .withEscapechar('\\')
                    .build();

            beanToCsv.write(writeList);
        } catch (Exception e) {
            log.error("写入csv文件失败!"+e.getMessage());
        }finally {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
    * List<T> 写入csv文件
    * <br/>
     * @param filePath      待生成的文件路径
     * @param writeList     bean对应实体类
     * @param headtitle     表头
     * @param codingFormat  对应格式 UTF-8 / gbk
     * @param additional    追加  true是追加。 false 是新建
     * @param time          数据循环遍数(该参数是测试使用)
    * @return [filePath, tClass, writeList, geshi]
    * @author zhouyiwei
    * @date 2022/3/24 19:48
    */
    public static  <T> void writeCsvAdd(String filePath,  List<T> writeList , List<String[]>  headtitle ,String codingFormat ,Boolean additional ,Integer time) {
        CharsetEncoder encoder = Charset.forName(codingFormat).newEncoder();
        CSVWriter csvWriter = null;
        Writer writer = null;
        //获取开始时间
        long startTime = System.currentTimeMillis();
        log.info("写入开始,时间为"+startTime);
        try{
            if(additional !=null && additional){
                writer = Files.newBufferedWriter(Paths.get(filePath),encoder.charset());
            }else{
                writer = new FileWriter(filePath,true);
            }
            // 普通writer转csvWriter
            csvWriter = new CSVWriter(writer);

            //写入表头。
            if(! headtitle.isEmpty()){
                for (String[]  title:headtitle){
                    //默认都是加引号的  boolean applyQuotesToAll 设置成 true ; 如果不加引号设置成false
                    csvWriter.writeNext(title,false);
                }
            }

            StatefulBeanToCsv<T> beanToCsv = new StatefulBeanToCsvBuilder<T>(csvWriter)
                    // withQuotechar(CSVWriter.DEFAULT_QUOTE_CHARACTER) 配置应用符号, 用单引号括起来
                    .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                    .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                    //  withApplyQuotesToAll(false) 设置最后文件是携带引号的
                    .withApplyQuotesToAll(false)
                    .withEscapechar('\\')
                    .build();

            for(int i = 0; i<time  ;i ++){
                beanToCsv.write(writeList);
            }


        } catch (Exception e) {
            log.error("写入csv文件失败!"+e.getMessage());
        }finally {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //获取结束时间
        long endTime = System.currentTimeMillis();
        log.info("写入结束,时间为"+endTime);

        log.info("开始到结束,时间为"+startTime + "--到--" + endTime);
        //输出程序运行时间
        log.info("写入程序运行时间:" + (endTime - startTime) + "ms;"  + (endTime - startTime) /1000 + "s;");
    }


    /**
     * 读取csv转List<T>
     * */
    public static <T> List<T> readCsv(File file, Class<T> clazz,String codingFormat) throws IOException {
        CsvBaseUtils.checkFile(file,CSV);
        InputStreamReader in = null;
        CsvToBean<T> csvToBean = null;
        try {
            in = new InputStreamReader(new BOMInputStream(new FileInputStream(file)), codingFormat);
            HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<>();
            strategy.setType(clazz);
            csvToBean = new CsvToBeanBuilder<T>(in)
                    .withSeparator(',')
                    .withMappingStrategy(strategy)
                    .build();
        } catch (Exception e) {
            log.error("读取csv文件失败!" + e.getMessage());
        }finally {
            in.close();
        }
        return csvToBean.parse();
    }

    /**
     * 读取csv转List<T> 通过迭代器处理
     * */
    public static <T> void readCsvIterator(File file, Class<T> clazz,String codingFormat) throws IOException {
        //获取开始时间
        long startTime = System.currentTimeMillis();
        log.info("读取开始,时间为"+startTime);
        CsvBaseUtils.checkFile(file,CSV);
        InputStreamReader in = null;
        in = new InputStreamReader(new BOMInputStream(new FileInputStream(file)), codingFormat);
        HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<>();
        strategy.setType(clazz);
        CsvToBean<T> csvToBean = null;
        try {
            csvToBean = new CsvToBeanBuilder<T>(in)
                    .withSeparator(',')
                    .withQuoteChar('\"')
                    .withMappingStrategy(strategy)
                    .withOrderedResults(false)
                    .build();


            int size = 0;
            Iterator iterator = csvToBean.iterator();
            for (Iterator it = iterator; it.hasNext(); ) {
                Object nextLine = it.next();
                // nextLine[] is an array of values from the line
//                log.info("展示数据为" + nextLine.toString());
                size++;
            }
            log.info("总数量" + size);

        } catch (Exception e) {
            log.error("读取csv文件失败!" + e.getMessage());
        }finally {
            in.close();
        }
        //获取结束时间
        long endTime = System.currentTimeMillis();
        log.info("读取结束,时间为"+endTime);

        log.info("读取到结束,时间为"+startTime + "--到--" + endTime);
        //输出程序运行时间
        log.info("读取程序运行时间:" + (endTime - startTime) + "ms;"  + (endTime - startTime) /1000 + "s;");
    }

}


后续也参考网上 进行了基本版本的添加

util - CsvBaseUtils

package com.fuhua.csvdemo.util;

import com.opencsv.bean.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
* opencsv 文件操作基本类
* <br/>
* @author zhouyiwei
* @date 2022/3/24 16:26
*/
@Slf4j
public class CsvBaseUtils {

    /**
    * 泛型实体转换为数组
    * <br/> 
    * @param beans	 泛型实体
    * @param needTitle	 返回数组是否是否需要标题
    * @return [beans]
    * @author zhouyiwei
    * @date 2022/3/26 10:45
    */
    public static <T> List<String[]> getStringArrayFromBean(List<T> beans , Boolean needTitle) {
        List<String[]> result = new ArrayList<String[]>();
        Class<? extends Object> cls = beans.get(0).getClass();
        Field[] declaredFields = cls.getDeclaredFields();
        List<Field> annoFields = new ArrayList<Field>();
        // 筛选出标有注解的字段
        for (Field field : declaredFields) {
            CsvBindByName anno = field.getAnnotation(CsvBindByName.class);
            if (anno != null) {
                annoFields.add(field);
            }
        }
        // 获取注解的值,即内容标题
        String[] title = new String[annoFields.size()];
        if(needTitle){
            for (int i = 0; i < annoFields.size(); i++) {
                title[i] = annoFields.get(i).getAnnotation(CsvBindByName.class).toString();
            }
            result.add(title);
        }
        try {
            // 获取内容
            for (T t : beans) {
                String[] item = new String[annoFields.size()];
                int index = 0;
                for (Field field : annoFields) {
                    String fieldName = field.getName();
                    String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    Method method = ReflectionUtils.findMethod(t.getClass(), methodName);
                    if (method != null) {
                        Object value = ReflectionUtils.invokeMethod(method, t);
                        if (value == null) {
                            item[index] = "";
                        } else {
                            item[index] = value.toString();
                        }
                    }
                    index++;
                }
                result.add(item);
            }
        } catch (Exception e) {
            log.info("实体对象转数组失败", e);
        }
        return result;
    }

    /**
     * 注解转换为返回数据的首行数据.
     * <br/>
     * @param clazz	 泛型实体
     * @return [beans]
     * @author zhouyiwei
     * @date 2022/3/26 10:45
     */
    public static <T> String[] getStringArrayFromtitle(Class<T> clazz ) {
        Class<? extends Object> cls = clazz;
        Field[] declaredFields = cls.getDeclaredFields();
        List<Field> annoFields = new ArrayList<Field>();
        // 筛选出标有注解的字段
        for (Field field : declaredFields) {
            CsvBindByName anno = field.getAnnotation(CsvBindByName.class);
            if (anno != null) {
                annoFields.add(field);
            }
        }
        // 获取注解的值,即内容标题
        String[] title = new String[annoFields.size()];
       for (int i = 0; i < annoFields.size(); i++) {
                title[i] = annoFields.get(i).getAnnotation(CsvBindByName.class).column();
            }
        return title;
    }

    /**
    * 数组转为对象集合
    * <br/> 
     * @param dataList	
     * @param bean
    * @return [dataList, bean]
    * @author zhouyiwei
    * @date 2022/3/26 11:05
    */
    public static <T> List<T> getBeanFromStringArray(List<String[]> dataList, Class<T> bean) {
        List<T> list = new ArrayList<>();
        List<Map<String, String>> titles = getTitles(dataList);
        Map<String, Field> fields = getFields(bean);
        try {
            for (Map<String, String> map : titles) {
                T t = bean.newInstance();
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    if (fields.containsKey(entry.getKey())) {
                        Field field = fields.get(entry.getKey());
                        Class<?> valType = field.getType();
                        String fieldName = field.getName();
                        String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                        Method method = ReflectionUtils.findMethod(bean, methodName, valType);
                        if (method != null) {
                            ReflectionUtils.invokeMethod(method, t, entry.getValue());
                        }
                    }
                }
                list.add(t);
            }
        }catch (Exception e) {
            log.error("创建实体失败", e);
        }
        return list;
    }

    /**
    *  数组标题与值的对应关系
    * <br/>
     * @param dataList
    * @return [dataList]
    * @author zhouyiwei
    * @date 2022/3/26 11:06
    */
    public static <T> List<Map<String, String>> getTitles(List<String[]> dataList) {
        List<Map<String, String>> list = new ArrayList<>();
        String[] titles = dataList.get(0);
        dataList.remove(0);
        for (String[] values : dataList) {
            Map<String, String> titleMap = new HashMap<>();
            for (int i = 0; i < values.length; i++) {
                titleMap.put(titles[i], values[i]);
            }
            list.add(titleMap);
        }
        return list;
    }

    /**
    * 注解名称与字段属性的对应关系
    * <br/>
    * @param clazz     实体对象类类型
    * @param <T>   泛型类型
    * @return [clazz] Map<String , Field>
    * @author zhouyiwei
    * @date 2022/3/26 11:15
    */
    public static <T> Map<String, Field> getFields(Class<T> clazz) {
        Map<String, Field> annoMap = new HashMap<>();
        Field[] fileds = clazz.getDeclaredFields();
        for (Field filed : fileds) {
            CsvBindByName anno = filed.getAnnotation(CsvBindByName.class);
            if (anno != null) {
                // 获取name属性值
                if (StringUtils.isNotBlank(anno.column())) {
                    annoMap.put(anno.column(), filed);
                }
            }
        }
        return annoMap;
    }

    /**
    * 创建文件对象
    * <br/>
     * @param filePath 文件路径,例如:temp/test.csv
    * @return [filePath]
    * @author zhouyiwei
    * @date 2022/3/26 11:17
    */
    public static File createFile(String filePath) {
        File file = null;
        try {
            // 创建文件目录
            file = new File(filePath.substring(0, filePath.lastIndexOf('/')));
            if (!file.exists()) {
                file.mkdirs();
            }
            // 创建文件对象
            file = new File(filePath);
            if (!file.exists() && file.createNewFile()) {
                log.info("创建文件对象成功");
            }
        }catch (IOException e) {
            log.error("创建文件对象失败", e);
        }
        return file;
    }

    /**
     * 删除该目录下所有文件
     * <br/>
     * @param filePath	文件目录路径,如:d:/test
     * @return [filePath]
     * @author zhouyiwei
     * @date 2022/3/26 10:33
     */
    public static  boolean deleteFiles(String filePath){
        File file = new File(filePath);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (File f : files) {
                    if (f.isFile() && f.delete()) {
                        log.info("删除" + f.getName() + "文件成功");
                    }
                }
                return true;
            }
        }
        return false;
    }

    /**
     * 删除单个文件
     * <br/>
     * @param filePath 文件目录路径,如:d:/test
     * @param fileName 文件名称,如:110.csv
     * @return [filePath, fileName]
     * @author zhouyiwei
     * @date 2022/3/26 10:35
     */
    public static boolean deleteFile(String filePath, String fileName) {
        File file = new File(filePath);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (File f : files) {
                    if (f.isFile() && f.getName().equals(fileName)) {
                        return f.delete();
                    }
                }
            }
        }
        return false;
    }

    /**
    * 校验文件是否存在
    * <br/>
     * @param file
     * @param fileSuffix	文件后缀
    * @return [file, fileSuffix]
    * @author zhouyiwei
    * @date 2022/3/26 11:21
    */
    public static void checkFile(File file , String fileSuffix) throws IOException {
        // 判断文件是否存在
        if (null == file) {
            throw new FileNotFoundException("文件不存在");
        }
        // 获得文件名
        String fileName = file.getName();
        // 判断文件是否是相同文件后缀文件 。比如是csv
        if (!fileName.endsWith(fileSuffix.toLowerCase()) && !fileName.endsWith(fileSuffix.toUpperCase())) {
            throw new IOException(fileName + "不是"+ fileSuffix +"文件");
        }
    }

}


其次是实体类的构建

entity - User.java

package com.fuhua.csvdemo.entity;

import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvBindByPosition;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


/**
* CSV文件测试实体类 - 超过30个字段
 * 原先 可以有参数是 Integer,或者其他的
 * 但是如果没设置值就是null, 本次对接需要对应参数 如果没有参数就是"" ,所以设置对应参数 统一设置为String,默认值为""
* <br/>
* @author zhouyiwei
* @date 2022/3/26 9:47
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {


    @CsvBindByName(column = "id")
    @CsvBindByPosition(position=0)
    private String id ;
    @CsvBindByName(column = "name")
    @CsvBindByPosition(position=1)
    private String name;

    /**
     * 原先 对应参数是 Integer,但是如果没设置值就是null, 本次对接需要对应参数 如果没有参数就是"" ,所以设置对应参数 统一设置为String,默认值为""
     * */
    @CsvBindByName(column = "age")
    @CsvBindByPosition(position=2)
    private String age ;
    @CsvBindByName(column = "department")
    @CsvBindByPosition(position=3)
    private String department;

    @CsvBindByName(column = "qq")
    @CsvBindByPosition(position=4)
    private String qq;
    @CsvBindByName(column = "weixin")
    @CsvBindByPosition(position=5)
    private String weixin;
    @CsvBindByName(column = "dingding")
    @CsvBindByPosition(position=6)
    private String dingding;
    @CsvBindByName(column = "email")
    @CsvBindByPosition(position=7)
    private String email;


    @CsvBindByName(column = "qq1")
    @CsvBindByPosition(position=8)
    private String qq1;
    @CsvBindByName(column = "weixin1")
    @CsvBindByPosition(position=9)
    private String weixin1;
    @CsvBindByName(column = "dingding1")
    @CsvBindByPosition(position=10)
    private String dingding1 ;
    @CsvBindByName(column = "email1")
    @CsvBindByPosition(position=11)
    private String email1;

    @CsvBindByName(column = "qq2")
    @CsvBindByPosition(position=12)
    private String qq2;
    @CsvBindByName(column = "weixin2")
    @CsvBindByPosition(position=13)
    private String weixin2;
    @CsvBindByName(column = "dingding2")
    @CsvBindByPosition(position=14)
    private String dingding2 ;
    @CsvBindByName(column = "email2")
    @CsvBindByPosition(position=15)
    private String email2;

    @CsvBindByName(column = "qq3")
    @CsvBindByPosition(position=16)
    private String qq3;
    @CsvBindByName(column = "weixin3")
    @CsvBindByPosition(position=17)
    private String weixin3;
    @CsvBindByName(column = "dingding3")
    @CsvBindByPosition(position=18)
    private String dingding3;
    @CsvBindByName(column = "email3")
    @CsvBindByPosition(position=19)
    private String email3;

    @CsvBindByName(column = "qq4")
    @CsvBindByPosition(position=20)
    private String qq4;
    @CsvBindByName(column = "weixin4")
    @CsvBindByPosition(position=21)
    private String weixin4;
    @CsvBindByName(column = "dingding4")
    @CsvBindByPosition(position=22)
    private String dingding4 ;
    @CsvBindByName(column = "email4")
    @CsvBindByPosition(position=23)
    private String email4;

    @CsvBindByName(column = "qq5")
    @CsvBindByPosition(position=24)
    private String qq5;
    @CsvBindByName(column = "weixin5")
    @CsvBindByPosition(position=25)
    private String weixin5;
    @CsvBindByName(column = "dingding5")
    @CsvBindByPosition(position=26)
    private String dingding5 ;
    @CsvBindByName(column = "email5")
    @CsvBindByPosition(position=27)
    private String email5;

    @CsvBindByName(column = "qq6")
    @CsvBindByPosition(position=28)
    private String qq6;
    @CsvBindByName(column = "weixin6")
    @CsvBindByPosition(position=29)
    private String weixin6;
    @CsvBindByName(column = "dingding6")
    @CsvBindByPosition(position=30)
    private String dingding6 ;
    @CsvBindByName(column = "email6")
    @CsvBindByPosition(position=31)
    private String email6;



}

进行test

test - CSVTest.java

package com.fuhua.csvdemo.test;

import com.fuhua.csvdemo.entity.User;
import com.fuhua.csvdemo.util.CsvBaseUtils;
import com.fuhua.csvdemo.util.CsvUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* 进行测试
* <br/>
* @author zhouyiwei
* @date 2022/3/26 11:24
*/
@Slf4j
public class CSVTest {

    private CsvBaseUtils csvBaseUtils;

    public static void main(String[] args) throws IOException {

        // 写入csv
        String path = "D:\\success80.csv";
        List<User> csvData = new ArrayList<>();
        User csv1= new User("哈皮","453454","10","100",
                "哈皮","453454","\"","100","哈皮","453454","","100",
                "哈皮","453454","","100","哈皮","453454","","100",
                "哈皮","453454","","100","哈皮","453454","","100",
                "哈皮","453454","","100");
        User csv2= new User("237869","傻逼","10","200",
                "哈皮","453454","","100","哈皮","453454","","100",
                "哈皮","453454","","100","哈皮","453454","","100",
                "哈皮","453454","","100","哈皮","453454","","100",
                "哈皮","453454","","100");
        csvData.add(csv1);
        csvData.add(csv2);


//        String codingFormat = "gbk";
        String codingFormat = "UTF-8";


        File file = new File("E:\\success100.csv");
//        CsvUtils.readCsvIterator(file, User.class,codingFormat);

        List<String[]> headtitle = new ArrayList<>();
        String[] title = CsvBaseUtils.getStringArrayFromtitle(User.class);
        headtitle.add(title);
        log.info("展示" + StringUtils.join(title, ","));


       CsvUtils.writeCsvAdd(path,csvData,headtitle,codingFormat,true ,3);
    }

}

其实test 比较凌乱,也是对应记录自我调试的过程。

4、测试数据以及结果。

写入效率。写入通过工作台打印,对应使用多线程,打印日志类型是debug

10条记录, 大概时间1350毫秒,1s;

100条数据, 大概时间1497 毫秒,1s;

1000条数据,大概时间3622毫秒,3s;

10000条数据,大概时间11833毫秒,11s;

100000,10w条数据, 耗时46435毫秒,46s,在数据相对简单情况下,大小为21095kb;

100w条数据,耗时 429s, 在数据相对简单情况下,大小为210938kb,是 206MB;

600w条数据,耗时 2572194ms。2572s。对应大小 为100w的 近6倍,即1236mb左右,1.5G

读取效率,相对写入数据速度要快。不过读取采用单线程。

600w条数据读取成bean,1352s,大约23分钟。

5、遇到困难,以及如何解决?

A、对应生成文件格式,默认是 UTF-8,但是之前的老项目实现对应格式是GBK?

关键代码是在文件生成时候,赋值对应编码格式类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-unpUdys6-1648295412400)(C:\Users\qijian\AppData\Roaming\Typora\typora-user-images\image-20220326193755939.png)]

进行处理,从而代码为

 
 // 处理对应 方法外传入的追加格式。 格式目前仅区分 UTF-8/gbk[需要小写]
 CharsetEncoder encoder = Charset.forName(codingFormat).newEncoder();
 
 //后续生成文件进行赋值
 writer = Files.newBufferedWriter(Paths.get(filePath),encoder.charset());

B、原生的写法 参照 对应方法writeCsv 即可实现。也就是有一个list bean 整个进行转换生成csv文件,并无表头设置。 后续优化方法 为 writeCsvAdd。 可以人工进行是否表头写入,对应表头信息根据对应 实体类中主键字段进行自动生成,以及通过csvWriter 进行追加,使用 csvWriter.writeNest实现,其中applyQuotesToAll为false是特意不加引号,因为业务需求。

C、如何进行中间信息的追加?

答: 在创建好文件之后,可以一直处理对应具体业务,不要关闭写的过程即可。demo中使用了for循环来代替中间处理业务逻辑过程。暂时没有很好的所谓本次方法调用结束,再对着已经存在文件进行后续编写。可能是对应方法找的不对吧。看后续需求。

D、目前仍有难题是,对应部分bean如果没有值,跟业务约定是传值"",目前仅实现生成"""",解析是可以解析成null,但是这个数据格式未找到很好方法处理。 目前已经将对应数据赋值处理成 “/”"。
20220327。该问题解决,对应字段赋值""。 同时 csvWriter = new CSVWriter(writer,CSVWriter.DEFAULT_SEPARATOR,CSVWriter.NO_QUOTE_CHARACTER,CSVWriter.NO_QUOTE_CHARACTER,CSVWriter.DEFAULT_LINE_END); 已经同步更新到gitee

以上代码跟官网5.6对应的文章整合成了中英 pdf,也会在gitee中统一放置。中文是根据谷歌翻译直接生成,所以部分细节翻译存在不准确性。以及5.x-4.x,4.x-3.x 变化中因为英文太多,所以页面翻译死机,直接用有道翻译复制直译,存在很大出入。需要自己辨别。

gitee 对应 网址为 https://gitee.com/zyiwei/opencsv。


漫漫长路,一个小周跟他一个小陈朋友一起努力奔跑。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值