poi解析csv文件

工具类

import javassist.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * @author: wmx
 * on 2022/5/7
 * 读取Excel得到对象集合,读取CSV(GBK编码---664行可修改编码格式)得到对象集合
 */
public class HPoiUtils {

    private static final String CLASSNAME = "genClass";

    /**
     * 供外部调用的参数最少的方法:根据文件生成对象集合
     * @param file 待处理Excel文件
     * @param listField 表头属性集合
     * @return 读取到的对象集合
     */
    //file listField
    public static List exe(File file, List<String> listField) {
        return exe(file, 0, listField, true);
    }

    //file listField hasHeader
    public static List exe(File file, List<String> listField, boolean hasHeader) {
        return exe(file, 0, listField, hasHeader);
    }

    //file sheet listField
    public static List exe(File file, Integer sheetIndex, List<String> listField) {
        return exe(file, sheetIndex, listField, true);
    }

    public static List exe(File file, String sheetName, List<String> listField) {
        return exe(file, sheetName, listField, true);
    }

    //file sheet listField hasHeader
    public static List exe(File file, Integer sheetIndex, List<String> listField, boolean hasHeader) {
        //生成类
        Class c = generateClass(listField);
        return exe(file, sheetIndex, listField, c, hasHeader);
    }

    public static List exe(File file, String sheetName, List<String> listField, boolean hasHeader) {
        //生成类
        Class c = generateClass(listField);
        return exe(file, sheetName, listField, c, hasHeader);
    }

    //file listField class
    public static List exe(File file, List<String> listField, Class c){
        return exe(file, 0, listField, c, true);
    }

    //file listField class hasHeader
    public static List exe(File file, List<String> listField, Class c, boolean hasHeader){
        return exe(file, 0, listField, c, hasHeader);
    }

    //file sheet listField class
    public static List exe(File file, Integer sheetIndex, List<String> listField, Class c){
        return exe(file, sheetIndex, listField, c, true);
    }

    public static List exe(File file, String sheetName, List<String> listField, Class c){
        return exe(file, sheetName, listField, c, true);//sheetName不区分大小写
    }

    /**
     * 供外部调用的全部参数的方法
     * @param file 文件
     * @param sheetIndex 读取的sheet索引值 从0开始
     * @param listField Excel表中每列对应的属性集合
     * @param c 类
     * @param hasHeader Excel是否有头部
     * @return 读取到的对象集合
     */
    //file sheet listField class hasHeader
    public static List exe(File file, Integer sheetIndex, List<String> listField, Class c, boolean hasHeader){
        //参数检查
        Boolean check = check(file, sheetIndex, listField, c);
        if(!check){
            return null;
        }

        //得到结果
        List listResultObj = generateResult(file, sheetIndex, listField, c, hasHeader);
        return listResultObj;
    }

    /**
     * 供外部调用的全部参数的方法
     * @param file 文件
     * @param sheetName 读取的sheet名字 不区分大小写
     * @param listField Excel表中每列对应的属性集合
     * @param c 类
     * @param hasHeader Excel是否有头部
     * @return 读取到的对象集合
     */
    public static List exe(File file, String sheetName, List<String> listField, Class c, boolean hasHeader){
        //参数检查
        Boolean check = check(file, sheetName, listField, c);
        if(!check){
            return null;
        }

        //得到结果
        List listResultObj = generateResult(file, sheetName, listField, c, hasHeader);
        return listResultObj;
    }


    /*******************************************************下面是私有方法*******************************************************************/

    private static List generateResult(File file, Integer sheetIndex, List<String> listField, Class c, boolean hasHeader) {
        Integer len = listField.size();
        List listResultStr = getStr(file, sheetIndex, len); //得到字符串数据集合
        return getObj(listField, listResultStr, c, hasHeader); //得到对象数据集合
    }

    private static List generateResult(File file, String sheetName, List<String> listField, Class c, boolean hasHeader) {
        Integer len = listField.size();
        List listResultStr = getStr(file, sheetName, len); //得到字符串数据集合
        return getObj(listField, listResultStr, c, hasHeader); //得到对象数据集合
    }


    /**
     * 根据属性集合生成类
     * @param listField 存放字段名
     * @return 动态生成的类
     * @throws NotFoundException
     * @throws CannotCompileException
     */
    private static Class generateClass(List<String> listField) {
        // 得到一个池
        ClassPool pool = ClassPool.getDefault();
        // 根据名称在运行期间动态生成一个类
        String className = HPoiUtils.class.getPackage().getName() + "." + CLASSNAME + ".java";
        // 根据类名 动态生成一个CtClass
        CtClass ctClass = pool.makeClass(className);

        // 制作字段
        List<FieldDeclare> fieldList = new ArrayList<>();
        for (String name : listField) {
            fieldList.add(new FieldDeclare(name));
        }

        // 向CtClass中添加字段和get set方法
        for (FieldDeclare filed : fieldList) {
            try {
                addFieldProperty(ctClass, filed.getName(), pool.getCtClass(filed.getClair()));
            } catch (CannotCompileException e) {
                System.out.println("添加字段失败");
                return null;
            } catch (NotFoundException e) {
                System.out.println("添加字段失败");
                return null;
            }
        }

        try {
            return ctClass.toClass();
        } catch (CannotCompileException e) {
            System.out.println("无法转化类");
            return null;
        }
    }

    /**
     * 向类中添加字段和getter setter方法
     * @param ctClass
     * @param fieldName
     * @param fieldClass
     */
    private static void addFieldProperty(CtClass ctClass, String fieldName, CtClass fieldClass) throws CannotCompileException {
        //生成私有属性
        CtField ctField = new CtField(fieldClass, fieldName, ctClass);
        ctField.setModifiers(Modifier.PRIVATE);
        //为类添加属性
        ctClass.addField(ctField);

        char[] cs = fieldName.toCharArray();
        if (cs[0] >= 97 && cs[0] <= 122) {
            cs[0] -= 32;
        }
        String getName = "get" + String.valueOf(cs);
        String setName = "set" + String.valueOf(cs);
        //添加get set方法
        ctClass.addMethod(CtNewMethod.getter(getName, ctField));
        ctClass.addMethod(CtNewMethod.setter(setName, ctField));
    }

    // 字段属性类
    static class FieldDeclare{
        private String clair; // 字段类型  可以通过字段类型名字得到字段类型的类  String -> Class
        private String name; // 字段名

        public FieldDeclare(String name) {
            this.clair = "java.lang.String";
            this.name = name;
        }

        public FieldDeclare(String clair, String name) {
            this.clair = clair;
            this.name = name;
        }

        public String getClair() {
            return clair;
        }

        public void setClair(String clair) {
            this.clair = clair;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }


    /**
     * 参数检查
     * @param file Excel文件
     * @param sheetIndex sheet索引值
     * @param listField 属性名称集合
     * @param c 对应类
     * @return 是否初始化成功
     * check存在的意义是做检查,检查到什么程度呢?检查到后面所有参数可以直接执行?为了不让最后走到哪了却没执行消耗太大?
     */
    private static Boolean check(File file, Integer sheetIndex, List<String> listField, Class c){
        try {
            //sheetIndex检查
            if (sheetIndex < 0) {
                System.out.println("sheet索引值不能为负数");
                return false;
            }
            //1、listField集合校验
            if (listField == null || listField.size() == 0) {
                System.out.println("listField集合为空, 表头元素对应属性名字的集合是必须的");
                return false;
            }
            for (String ex : listField) {
                if(StringUtils.isEmpty(ex)){
                    System.out.println("listField中不允许出现空字符串");
                    return false;
                }
            }

            //2、文件校验
            String path = file.getPath();

            try (  InputStream inTemp = new FileInputStream(path) ){
                if (inTemp == null) {//有必要吗
                    System.out.println("无法得到文件流");
                    return false;
                }
            } catch (FileNotFoundException e) {
                System.out.println("文件路径错误或在这个路径下找不到此文件");
                return false;
            }

            if (c == null) {
                System.out.println("c为空,Class是必须的");
                return false;
            }
            return true;
        }catch (Exception e){
            System.out.println("HPoiUtils - - - 未知的初始化错误...");
        }
        return false;
    }

    private static Boolean check(File file, String sheetName, List<String> listField, Class c){
        try {
            //sheetName检查
            if (sheetName == null || "".equals(sheetName)) {
                System.out.println("sheet名字不能为空");
                return false;
            }
            //1、listField集合校验
            if (listField == null || listField.size() == 0) {
                System.out.println("listField集合为空, 表头元素对应属性名字的集合是必须的");
                return false;
            }
            for (String ex : listField) {
                if(StringUtils.isEmpty(ex)){
                    System.out.println("listField中不允许出现空字符串");
                    return false;
                }
            }

            //2、文件校验
            String path = file.getPath();

            try (  InputStream inTemp = new FileInputStream(path) ){
                if (inTemp == null) {//有必要吗
                    System.out.println("无法得到文件流");
                    return false;
                }
            } catch (FileNotFoundException e) {
                System.out.println("文件路径错误或在这个路径下找不到此文件");
                return false;
            }

            if (c == null) {
                System.out.println("c为空,Class是必须的");
                return false;
            }
            return true;
        }catch (Exception e){
            System.out.println("HPoiUtils - - - 未知的初始化错误...");
        }
        return false;
    }


    /**
     * 字符串数据对象化
     * @param listField 字段集合
     * @param listResultStr 字符串结果集合
     * @param c 类
     * @param hasHeader excel中是否有表头
     * @return
     */
    private static List getObj(List<String> listField, List<String> listResultStr, Class c, boolean hasHeader){
        //字符串集合对象化
        int fieldNum = listField.size();//属性个数
        int lenResultStr = listResultStr.size();//Excel中的数据总量
        List listResultObj = new ArrayList(lenResultStr / fieldNum);//结果对象, 设置的容量可能会多一个 hasHeader : true

        int index = hasHeader ? fieldNum : 0;//从第哪个下标开始读取listResultStr中的数据
        //循环读取ListS, 每一个for循环封装一个对象
        for ( ; index < lenResultStr; index += fieldNum) {
            try {
                Object o = c.newInstance();//准备实例
                //循环set对象的fieldNum个属性值。一个循环后则一个对象包装完成
                for (int j = 0; j < fieldNum; j++) {
                    if (index + j < lenResultStr) {//大步长 + 小步长 确定了数据在ListS中的索引值
                        String dataStr = listResultStr.get(index + j);//拿到一个数据
                        if(StringUtils.isNotBlank(dataStr)){//如果数据为nul或者""那么直接跳过,最后对象中此属性为null
                            String filedName = listField.get(j);
                            invokeSetterByName(c, o, filedName, dataStr);
                        }//if
                    }//if
                }
                listResultObj.add(o);//装入集合之后该做什么了呢
            }catch (Exception e){
                e.printStackTrace();
            }
        }//for
        return listResultObj;
    }

    /**
     * 为对象执行属性的setter方法:1、生成setter方法,2、将数据转化为对应正确的类型,3、执行setter方法
     * @param c 目标类
     * @param o 目标对象
     * @param filedName 属性名字
     * @param dataStr 属性值
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private static void invokeSetterByName(Class c, Object o, String filedName, String dataStr) throws IllegalAccessException, InvocationTargetException {
        String setterMethodName = getSetterMethodName(filedName);
        Method[] methods = c.getDeclaredMethods();//拿到所有方法
        for (Method method : methods) {
            if(setterMethodName.equals(method.getName())){//必须得到同名的方法,然后获取到setter()参数类型,
                //要先判断method的参数类型
                Class<?>[] types = method.getParameterTypes();
                String typeName = types[0].getName();//类型名称 java.lang.Float
                Object data = regression(typeName, dataStr);//根据类型名称将String数据转换成需要的类型的数据  sD已经判断过不为空了
                method.invoke(o,data);//执行set方法
                break;//跳出for循环
                //应该加一个标识,sign = 1 如果sign == 0 那么说明没有进入for循环,那么就说明没有setXxx的方法,就说明这个表头字段错了
            }
        }//for
    }

    /**
     * 获取setter方法名字
     * @param filedName 属性名
     * @return username -> setUsername
     */
    private static String getSetterMethodName(String filedName) {
        StringBuilder sb = new StringBuilder();
        sb.append("set");
        return sb.append(Tran(filedName)).toString();
    }

    /**
     * 从文件中得到String类型的数据
     * @param file 文件
     * @param len excel文件表头长度
     * @return string数据集合
     */
    private static List getStr(File file, Integer sheetIndex, Integer len){
        //分情况处理Excel
        String path = file.getPath();
        InputStream in = null;
        try {
            in = new FileInputStream(path);
        } catch (FileNotFoundException e) {
            System.out.println("文件路径错误或在这个路径下找不到此文件");
            return null;
        }
        List listResultStr = null;
        try {
            String s = StringUtils.substringAfterLast(path, ".");//文件名,分割
            if("xls".equals(s)){
                listResultStr = doXls(in,sheetIndex,len);
            }else if("xlsx".equals(s)){
                listResultStr = doXlsx(in,sheetIndex,len);
            }else{
                System.out.println("文件格式不支持,请选择xls或xlsx格式的Excel文件");
            }
        } catch (IOException e) {
            System.out.println("通过文件流获取Excel对象失败");
        } finally {
            try {
                in.close();//关闭文件/流
            } catch (IOException e) {
                System.out.println("关闭文件流失败");
            }
        }
        return listResultStr;
    }

    private static List getStr(File file, String sheetName, Integer len){
        //分情况处理Excel
        String path = file.getPath();
        InputStream in = null;
        try {
            in = new FileInputStream(path);
        } catch (FileNotFoundException e) {
            System.out.println("文件路径错误或在这个路径下找不到此文件");
            return null;
        }
        List listResultStr = null;
        try {
            String s = StringUtils.substringAfterLast(path, ".");//文件名,分割
            if("xls".equals(s)){
                listResultStr = doXls(in,sheetName,len);
            }else if("xlsx".equals(s)){
                listResultStr = doXlsx(in,sheetName,len);
            }else{
                System.out.println("文件格式不支持,请选择xls或xlsx格式的Excel文件");
            }
        } catch (IOException e) {
            System.out.println("通过文件流获取Excel对象失败");
        } finally {
            try {
                in.close();//关闭文件/流
            } catch (IOException e) {
                System.out.println("关闭文件流失败");
            }
        }
        return listResultStr;
    }

    /**
     * 读取xls文件
     * @param in 文件输入流
     * @param len 最大列数
     * @throws IOException
     */
    private static List doXls(InputStream in, Integer sheetIndex, Integer len) throws IOException {
        List<String> listResultStr = new ArrayList();
        //获取Excel文件对象
        HSSFWorkbook workbook = new HSSFWorkbook(in);
        //获取sheet表对象
        HSSFSheet sheet = workbook.getSheetAt(sheetIndex);//只允许有一个sheet表
        int nRow = sheet.getLastRowNum();//若excel表中有3行,那么nRow=2 : 0,1,2
        for(int i=0; i <= nRow; i++){
            HSSFRow row = sheet.getRow(i);//row:第i+1行
            if(row != null)
                for(int j = 0; j < len; j++){
                    HSSFCell cell = row.getCell(j);//cell:第i+1行第j+1列单元格
                    if(cell == null){
                        listResultStr.add("");
                    }else{
                        String str = cell.toString();
                        listResultStr.add(str);
                    }
                }
        }
        return listResultStr;
    }

    private static List doXls(InputStream in, String sheetName, Integer len) throws IOException {
        List<String> listResultStr = new ArrayList();
        //获取Excel文件对象
        HSSFWorkbook workbook = new HSSFWorkbook(in);
        //获取sheet表对象
        final HSSFSheet sheet = workbook.getSheet(sheetName);
        int nRow = sheet.getLastRowNum();//若excel表中有3行,那么nRow=2 : 0,1,2
        for(int i=0; i <= nRow; i++){
            HSSFRow row = sheet.getRow(i);//row:第i+1行
            if(row != null)
                for(int j = 0; j < len; j++){
                    HSSFCell cell = row.getCell(j);//cell:第i+1行第j+1列单元格
                    if(cell == null){
                        listResultStr.add("");
                    }else{
                        String str = cell.toString();
                        listResultStr.add(str);
                    }
                }
        }
        return listResultStr;
    }

    /**
     * 读取xlsx文件
     * @param in
     * @param len
     * @throws IOException
     */
    private static List doXlsx(InputStream in, Integer sheetIndex, Integer len) throws IOException {
        List<String> listResultStr = new ArrayList();
        XSSFWorkbook workbook = new XSSFWorkbook(in);
        XSSFSheet sheet = workbook.getSheetAt(sheetIndex);
        int nRow = sheet.getLastRowNum();
        for(int i = 0; i <= nRow; i++){
            XSSFRow row = sheet.getRow(i);
            if(row != null) //不会读取空行
                for(int j = 0; j < len; j++){
                    XSSFCell cell = row.getCell(j);
                    if(cell == null){
                        listResultStr.add("");
                    }else {
                        String str = cell.toString();
                        listResultStr.add(str);
                    }
                }
        }
        return listResultStr;
    }

    private static List doXlsx(InputStream in, String sheetName, Integer len) throws IOException {
        List<String> listResultStr = new ArrayList();
        XSSFWorkbook workbook = new XSSFWorkbook(in);
        final XSSFSheet sheet = workbook.getSheet(sheetName);
        int nRow = sheet.getLastRowNum();
        for(int i = 0; i <= nRow; i++){
            XSSFRow row = sheet.getRow(i);
            if(row != null)
                for(int j = 0; j < len; j++){
                    XSSFCell cell = row.getCell(j);
                    if(cell == null){
                        listResultStr.add("");
                    }else {
                        String str = cell.toString();
                        listResultStr.add(str);
                    }
                }
        }
        return listResultStr;
    }

    /**
     * 类型回归
     * @param typeName 类型名
     * @param dataStr 字段名
     * @return 将String类型的字段转化为对应类型的字段
     * 目前好像只能转化为 java.lang.Integer java.lang.Float java.lang.String
     */
    private static Object regression(String typeName,String dataStr){
        if (typeName.contains("Integer")) {
            int n = dataStr.indexOf(".");
            if(n > 0) dataStr = dataStr.substring(0, n);
        }
        try {
            Class<?> c = Class.forName(typeName);
            Constructor<?> constructor = c.getConstructor(String.class);//Float有一个传入String字符串的构造方法
            Object o = constructor.newInstance(dataStr);
            return o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 字符串首字母转大写。(反射时通过属性名得到对应setter方法处使用)
     * @param s 原字符串
     * @return 转换后的字符串
     */
    private static String Tran(String s){
        char[] chars = s.toCharArray();
        if (chars[0] >= 97 && chars[0] <= 122)
            chars[0] -= 32;
        return String.valueOf(chars);
    }


    /**
     * 读取csv文件数据
     * @param file 文件
     * @param listField 文件各列对应的属性集合
     * @param c 类
     * @param hasHeader 是否有头
     * @return 读取到的对象集合
     */
    public static List exeCsv(File file, List listField, Class c, boolean hasHeader,String codeType, int rowPar) {
        //参数检查
        Boolean check = check(file, 0, listField, c);
        if(!check){
            return null;
        }
        //得到结果
        List listResultObj = generateResultCSV(file, listField, c, hasHeader,codeType,rowPar);
        return listResultObj;
    }

    public static List exeCsv(File file, List listField, Class c,String codeType, int rowPar) {
        return exeCsv(file, listField, c, true,codeType,rowPar);
    }

    public static List exeCsv(File file, List listField,String codeType, int rowPar) {
        final Class c = generateClass(listField);
        return exeCsv(file, listField, c, true,codeType,rowPar);
    }

    private static List generateResultCSV(File file, List<String> listField, Class c, boolean hasHeader,String codeType, int rowPar) {
        List listResultStr = readCSV(file,codeType,rowPar); //得到字符串数据集合
        return getObj(listField, listResultStr, c, hasHeader); //得到对象数据集合
    }

    /**
     * 读取csv文件
     * @param file 文件
     * @return 读取到的字符串集合
     * 读取策略:读取每行的全部内容,空也会读取
     */
    public static List<String> readCSV(File file,String codeType, int rowPar){
        List<String> listResultStr = new ArrayList<>(10);
        try ( BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file),codeType)) ){
            String line = null;
            String[] items = null;
            while((line = bufferedReader.readLine()) != null){
                //数据行
                items = line.split(",", rowPar);
                listResultStr.addAll(Arrays.asList(items));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return listResultStr;
    }
}

调用

List<QizhiVideoAccountStateModel> list = new ArrayList<>();
        List<String> listField = genListField();
        //执行
//        poi解析文件 文件编码类型为GBK
//        由于csv文件的特性,根据,进行,分割数据,每行分隔为8(文件的表头列数)部分 传错数值会导致程序运行失败(失败原因可能是某个数之中包含,导致之后的数据全部错误)
        list = HPoiUtils.exeCsv(new File(url), listField, QizhiVideoAccountStateModel.class,"GBK",8);
//准备属性集合list
    private static List<String> genListField() {
        List<String> listField = new ArrayList(10);//建议使用ArrayList,get(i)操作更快
        listField.add("assets_name");//实体类中的字段
        listField.add("assets_ip");
        listField.add("sys_account_name");
        listField.add("executor");
        listField.add("operate_type");
        listField.add("end_time");
        listField.add("result_detail");
        listField.add("detail");
        return listField;
    }

csv文件截图
在这里插入图片描述

pom文件

<!--poi-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<!--javassist.*-->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.18.2-GA</version>
</dependency>
<!--工具类-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.5</version>
</dependency>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值