`
liyebing
  • 浏览: 56928 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

实现自己的csv文件解析引擎

 
阅读更多

前言:

   这里仅仅支持Excel文件导出的CSV文件,解析的核心是一个正则表达式,这个正则表达式取自<精通正则表达式>一书中,感谢作者。

 

1、解析引擎结构图

   

 

2、很懒很懒,直接上代码了

 

 /**
     * CSV 文件解析
     * 
     * @param <T>
     * @param xmlInputStream
     * @param clazz
     * @param file
     * @return
     */
    protected <T> List<T> parse(InputStream xmlInputStream, Class<T> clazz, InputStream file) {

        //xml解析
        Map<String, String> metaDataMap = parseXmlConfig(xmlInputStream);

        //获取对象实例
        T obj = getInstance(clazz);

        //校验Map中的metaData信息与clazz中的属性是否完全匹配
        checkProperty(metaDataMap, obj);

        //读取csv文件,返回解析结果
        List<T> datas = parseCsvFile(file, clazz, metaDataMap);

        return datas;
    }



 /**
     * 获取对象属性与csv头部文件的映射Map
     * key:csv文件头部中文
     * value:映射类的属性
     * 
     * @param xmlPath
     * @return
     */
    @SuppressWarnings("unchecked")
    protected Map<String, String> parseXmlConfig(InputStream in) {
        Map<String, String> metaDataMap = new HashMap<String, String>();
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(in);
            Element root = document.getRootElement();

            //循环模板(*-*!!)
            for (Iterator iter = root.elementIterator(); iter.hasNext();) {
                Element element = (Element) iter.next();
                getPropertyValue(element, "name", metaDataMap);
            }
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        return metaDataMap;
    }


 /**
     * 获取映射对象的运行实例
     * 
     * @param <T>
     * @param clazz
     * @return
     */
    private <T> T getInstance(Class<T> clazz) {
        T obj = null;

        try {
            obj = clazz.newInstance();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return obj;
    }


 /**
     * 校验Map中的metaData信息与clazz中的属性是否完全匹配
     * 
     * @param <T>
     * @param metaDataMap  key:中文描述  value:类属性
     * @param obj
     */
    private <T> void checkProperty(Map<String, String> metaDataMap, T obj) {
        List<String> fieldList = new ArrayList<String>();

        //获取obj属性名称列表
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            String name = f.getName();
            if (!StringUtil.equals(name, ConstantEnum.REFLECT_FIELD_GARGABE_ONE.getCode())
                && !StringUtil.equals(name, ConstantEnum.REFLECT_FIELD_GARGABE_TWO.getCode())) {
                fieldList.add(f.getName());
            }
        }

        for (String fieldName : fieldList) {
            if (!metaDataMap.containsValue(fieldName)) {
                throw new RevmngException(RevmngResultCode.HEAD_INFO_NOT_SAME_OBJ);
            }
        }
        if (metaDataMap.size() != fieldList.size()) {
            throw new RevmngException(RevmngResultCode.HEAD_INFO_NOT_SAME_OBJ);
        }
    }


  /**
     * 解析csv文件
     * 
     * @param <T>
     * @param file
     * @param obj
     * @param metaDataMap key:中文  value:字段属性
     * 
     * @return
     */
    private <T> List<T> parseCsvFile(InputStream file, Class<T> clazz,
                                     Map<String, String> metaDataMap) {
        List<T> datas = new ArrayList<T>();
        InputStreamReader fr = new InputStreamReader(file);
        BufferedReader br = new BufferedReader(fr);
        List<String> headInfo = new ArrayList<String>();

        try {
            String line = "";
            int lineSeq = 0;
            while ((line = br.readLine()) != null) {
                T tempObj = getInstance(clazz);
                int cellSeq = -1;
                Map<String, String> mapLine = new HashMap<String, String>();

                lineSeq++;
                Matcher matcher = getMatcher(line);
                Matcher mQuote = Pattern.compile("\"\"").matcher("");

                while (matcher.find()) {
                    cellSeq++;
                    String field = getField(matcher, mQuote);

                    if (lineSeq == 1) {
                        //头部信息
                        if (StringUtil.isNotBlank(field)) {
                            headInfo.add(field);
                        }
                        continue;
                    }
                    //映射类的属性名称
                    if (cellSeq >= headInfo.size()) {
                        continue;
                    }
                    String propertyName = metaDataMap.get(headInfo.get(cellSeq));
                    if (StringUtil.isBlank(propertyName)) {
                        logger.warn("未取到导入文件头部的文字信息属性!");
                        throw new RevmngException(RevmngResultCode.CSV_HEAD_INFO_ERROR);
                    }
                    mapLine.put(propertyName, field);
                }
                //解决这个正则的一个缺陷,类似这样的csv格式解析有误",a,bab,a,c,c"(第一个单元格数据为空),现在会直接跳过
                firstCellIsNotNull(cellSeq, line, headInfo);
                //填充映射对象的属性值
                if (lineSeq > 1) {
                    if (headInfo.size() != metaDataMap.size()) {
                        logger.warn("上传文件的模板不正确,请下载正确的模板!");
                        throw new RevmngException(RevmngResultCode.CSV_TEMPLATE_FILE_ERROR);
                    }
                    setObjectValue(tempObj, mapLine);
                    datas.add(tempObj);
                }
            }

        } catch (RevmngException re) {
            throw re;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return datas;
    }

    /**
     * 解决这个正则的一个缺陷,类似这样的csv格式解析有误",a,bab,a,c,c"(第一个单元格数据为空),现在会直接跳过
     * 
     * @param cellSeq 
     * @param line
     */
    @SuppressWarnings("unchecked")
    private void firstCellIsNotNull(int cellSeq, String line, List<String> headInfo) {
        if (StringUtil.isBlank(line)) {
            return;
        }
        String[] contens = line.split("[,]");
        List<String> lists = Arrays.asList(contens);
        StringBuffer lineBuffer = new StringBuffer();
        for (int i = 0; i < headInfo.size(); i++) {
            lineBuffer.append(headInfo.get(i)).append(" : ");
            if (i < lists.size()) {
                lineBuffer.append(lists.get(i));
            }
        }

        if (!CollectionUtils.isEmpty(lists) && cellSeq == 0) {
            logger.warn("存在第一个单元格数据为空的文本行!line:" + line);
            throw new RevmngException(RevmngResultCode.CSV_FIRST_CELL_NOT_NULL.getCode(),
                "数据行: " + lineBuffer.toString() + " 的 " + lists.get(0) + "不允许为空!");
        }
    }

    /**
     * 获取Matcher
     * @param line
     * @return
     */
    private Matcher getMatcher(String line) {
        Matcher matcher = Pattern.compile(RegularExpressionEnum.REGEX_CSV_FOMAT.getCode(),
            Pattern.COMMENTS).matcher("");
        matcher.reset(line);
        return matcher;
    }

    /**
     * 获取解析的一个单元值
     * @param matcher
     * @param mQuote
     * @return
     */
    private String getField(Matcher matcher, Matcher mQuote) {
        String field = "";
        if (matcher.start(2) >= 0)
            field = matcher.group(2);
        else
            field = mQuote.reset(matcher.group(1)).replaceAll("\"");
        return field;
    }



    /**
     * 设置一行映射对象的属性值
     * 
     * @param <T>
     * @param object
     * @param mapLine key :属性名称   value:属性值
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     */
    private <T> void setObjectValue(T object, Map<String, String> mapLine)
                                                                          throws IllegalArgumentException,
                                                                          IllegalAccessException {
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            String name = f.getName();
            //去除垃圾属性的影响
            if (StringUtil.equals(name, ConstantEnum.REFLECT_FIELD_GARGABE_ONE.getCode())
                || StringUtil.equals(name, ConstantEnum.REFLECT_FIELD_GARGABE_TWO.getCode())) {
                continue;
            }
            if (mapLine.containsKey(f.getName())) {
                //去空格
                String value = StringUtil.trim(mapLine.get(f.getName()));
                f.set(object, value);
            }
        }
    }

 

 

 

只是一些关键代码而已,别人不一定看得明白,自己mark一下。。哇哈哈哈。。。

 

 

 

 

 

  • 大小: 83.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics