`
liyebing
  • 浏览: 58049 次
  • 性别: 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
分享到:
评论

相关推荐

    ado合并文件多个csv文件

    本篇文章将详细介绍如何使用ADO(ActiveX Data Objects)技术来实现多个CSV文件的合并。 #### 二、ADO简介 ADO是一种用于访问数据的技术,它提供了简单且一致的方式与不同类型的数据库进行交互。ADO通过OLE DB提供...

    Node.js-neat-csv-快速的CSV解析器

    `neat-csv` 的设计目标是提供高效且易于使用的 CSV 解析功能,它能够处理大量数据,并且支持通过回调接口进行异步操作,这对于处理大文件或者实时流数据非常有用。 以下是一些关于 `neat-csv` 的关键知识点: 1. *...

    libcsv-:由C ++实现的csv库。 该库可用于解析,修改和输出csv文件

    "libcsv-" 是一个C++编写的CSV(逗号分隔值)库,它提供了处理CSV文件的全面功能,包括解析、编辑和写入操作。这个库对于那些需要在C++项目中与CSV数据打交道的开发者来说非常有用。 **描述详解:** libcsv++是一...

    文本文件解析对象

    在实际应用中,文本文件解析对象会涉及文件读取(如使用fopen、readline等函数)、字符串处理(如split、join、replace等操作)、数据格式转换(如CSV转JSON、XML等)以及可能的数据验证和清洗步骤。理解并有效地...

    Tad是一个桌面应用程序查看和分析tabular数据比如CSV文件

    CSV文件是一种广泛使用的数据格式,它以纯文本形式存储表格数据,便于在不同程序之间交换数据。Tad提供了一个直观的用户界面,让用户能够高效地浏览、操作和理解这些数据。 描述中的信息进一步强调了Tad的核心功能...

    CSV.rar_cocos2dx_csv

    1. CSV文件解析基础: CSV文件由行和列组成,每行数据之间用换行符分隔,列数据之间用逗号分隔。例如: ``` Name,Age,Job John,30,Engineer Jane,25,Doctor ``` 这种格式使得CSV文件易于阅读和处理,可以用...

    csv2es:将 csv 文件流导入 ES

    标题 "csv2es:将 csv 文件流导入 ES" 指的是一个用于将逗号分隔值(CSV)文件的数据导入到 Elasticsearch (ES) 的工具或库。这个工具主要适用于那些需要快速、批量地将结构化数据从 CSV 文件导入到 ES 数据存储中的...

    基于cocos2dx写的CSV读取例子

    总结来说,Cocos2d-x项目中读取CSV文件的关键在于利用C++标准库的功能,通过`fstream`打开文件,然后使用`istringstream`和分隔符来解析每一行的内容。这个过程可以灵活地适应各种数据结构,使得CSV文件成为一个有效...

    csv导入sqlite工具

    - 打开CSV文件:使用合适的文本编辑器或工具确认CSV文件为UTF-8编码,避免乱码问题。 - 导入数据: - 直接SQL命令:使用`LOAD DATA INFILE`语句,但SQLite原生不支持此命令,需要借助第三方工具或编程实现。 - ...

    解决pandas中读取中文名称的csv文件报错的问题

    通过这个简单的修改,Pandas应该能够成功读取并解析含有中文标题的CSV文件。不过,这也提醒我们,对于特定的编程任务,性能和功能之间可能存在权衡。在追求效率的同时,我们也需要确保我们的代码能够处理各种边缘...

    Excel转CSV程序

    这就引出了转换为CSV格式的需求,因为CSV文件仅包含基本的表格数据,没有Excel的样式、公式或图表等复杂元素,这使得它们能被大多数编程语言和数据库管理系统轻松解析。 CSV文件的结构简单,由逗号分隔的数据项组成...

    name-translate:将名称从CSV文件中的印地语转换为英语,然后将其下载为带有已翻译名称的csv文件

    4. JavaScript:作为项目的主要编程语言,JavaScript负责读取CSV文件,调用Google Cloud Translation API,处理翻译结果,并将数据写回到新的CSV文件中。JavaScript的Node.js环境使得可以在服务器端执行这些任务。 ...

    Unity CSV转C# 工具

    通过将CSV文件转换为C#类,开发者可以更方便地在Unity项目中读取和操作这些数据,而无需编写大量的解析代码。 Unity引擎广泛应用于游戏开发,它支持C#编程语言,因此将CSV数据转换为C#类有助于提高开发效率和代码可...

    CSV联接:一种命令行工具,用于在C#.NET Core中对CSV文件执行完全外部联接

    用于在C#.NET Core中对CSV文件执行完全外部联接的命令行工具: CsvJoin.exe Data sales.csv new_sales.csv &gt; joined_sales.csv 特征: 针对CSV文件执行SQL 将结果保存到CSV 保存自动生成SQL 先决条件: ...

    C++可识别的excel对应的.csv文本的读写

    在C++中,没有内置的库直接支持Excel文件,但我们可以通过第三方库,如`libcsv`、`pugixml`或`Boost.IOStreams`等,实现读写CSV文件的功能。 1. **读取CSV文件** - 使用标准库:你可以使用`fstream`类读取文件,...

    Excel表格批量转CSV、Lua工具

    转换后的CSV文件可以直接在Unity中导入,然后通过C#脚本来读取和解析数据。 `xls2lua`工具则更进一步,它不仅转换数据格式,还可能包含了一些针对Lua的特定优化,比如生成可以直接在Lua环境中运行的代码结构。Lua...

    vcf 转 csv

    要将VCF文件转换为CSV格式,我们需要一个能够解析VCF文件并将其内容写入CSV文件的工具。在这个场景中,"vcf-to-csv-converter.exe" 是一个专门为此目的设计的程序。然而,使用这个工具之前,需要确保您的计算机上...

    Unity Excel文件转换为JSON、CSV和XML和Lua

    它提供了一种快速、便捷的方法,将Excel文件转换成JSON、CSV、XML以及Lua这四种常见的数据格式,使得Unity项目能够轻松地加载和解析这些数据。 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,...

    从txt文件中读取内容进行解析存储到sqlite中

    2. **内容解析**:读取的TXT文件内容可能包含结构化的数据,如CSV格式(逗号分隔值)或其他自定义格式。解析过程通常涉及分割文本,识别字段,以及处理可能的嵌套结构。例如,CSV数据可以通过Python的`csv`库解析;...

    解析csv数据导入mysql的方法

    CSV文件因其简单性而被广泛使用,是存储和交换数据的一个非常方便的格式。MySQL数据库管理系统提供了一种高效的导入CSV数据的方式,即通过MySQL的CSV存储引擎。 MySQL的CSV存储引擎允许用户直接将CSV格式的文件导入...

Global site tag (gtag.js) - Google Analytics