# dp2 **Repository Path**: mirrors_6tail/dp2 ## Basic Information - **Project Name**: dp2 - **Description**: a common data parser tool, support reading and writing xls, xlsx, doc, docx, csv.一个通用的表格数据读写工具,支持xls、xlsx、doc、docx、csv格式。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-10-22 - **Last Updated**: 2026-03-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # dp2 [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/6tail/dp2/blob/master/LICENSE) 一个通用的表格数据读写工具,支持xls、xlsx、doc、docx、csv格式。 > 支持在较低内存占用下完成超大xls和xlsx文件的解析。 > 支持直接生成新文件,也支持在模板文件中修改单元格数据并生成新的文件。 > 支持java1.5及以上版本。java1.5需额外引入javax包,否则解析xlsx会报错。 > xls和xlsx文件仅解析第一个Sheet。 > doc和docx文件仅解析第一个表格。 ## 使用 通过maven引入或者[点此下载](https://github.com/6tail/dp2/releases)相应的jar。 ```xml cn.6tail dp2 1.0.3 ``` ## 示例 ### 待解析excel内容
A B C D E
1 序号 姓名 性别 年龄 民族
2 1 张三 20 汉族
3 2 李四 18 汉族
4 3 王二 30 满族
### 自动读取示例 // 待解析文件 File file = new File("template.xls"); // 自动获取标记 List markers = SingleLineRepeatMarkerDetector.detect(file); // 通过工厂获取解析器接口 IParser parser = ParserFactory.getParser(file); // 获取节点读取器 INodeReader reader = parser.read(markers); // 遍历所有找到的节点 while (reader.hasNext()) { INode node = reader.next(); // 自动识别的标题以head作为标记名称,以body作为数据标记名称 if ("head".equals(node.getMarker().getName())) { // 表头不处理 } else if ("body".equals(node.getMarker().getName())) { for (INode child : node.getChildren()) { // 自动识别的以列下标(从0开始)作为子项标记名称 // System.out.print(child.getMarker().getName() + "="); System.out.print(child.getValue()); System.out.print("\t"); } System.out.println("_____________________________________"); } } ### 手动读取示例 // 待解析文件 File file = new File("template.xls"); // 定义待解析的标记列表 List markers = new ArrayList(); // 标题只有一行,直接使用Marker,位于行0列0(如果不解析标题,则可以不定义) Marker markerHead = new Marker("标题", 0, 0); // 设置宽度为5列(高度默认为一行不用设置了) markerHead.setWidth(5); // 添加需要取的标题标记及位于父区域内的坐标 markerHead.addChild(new Marker("序号", 0, 0)); markerHead.addChild(new Marker("姓名", 0, 1)); markerHead.addChild(new Marker("性别", 0, 2)); markerHead.addChild(new Marker("年龄", 0, 3)); markerHead.addChild(new Marker("民族", 0, 4)); // 数据区域为重复性数据,使用RepeatedMarker,位于行1列0 Marker markerBody = new RepeatedMarker("数据", 1, 0); // 设置宽度为5列(高度默认为一行不用设置了) markerBody.setWidth(5); // 添加需要取的数据标记及位于父区域内的坐标 markerBody.addChild(new Marker("序号", 0, 0)); markerBody.addChild(new Marker("姓名", 0, 1)); markerBody.addChild(new Marker("性别", 0, 2)); markerBody.addChild(new Marker("年龄", 0, 3)); markerBody.addChild(new Marker("民族", 0, 4)); // 添加要解析的标记 markers.add(markerHead); markers.add(markerBody); // 通过工厂获取解析器接口 IParser parser = ParserFactory.getParser(file); // 获取节点读取器 INodeReader reader = parser.read(markers); // 遍历所有找到的节点 while (reader.hasNext()) { INode node = reader.next(); if ("标题".equals(node.getMarker().getName())) { // 表头不处理 } else if ("数据".equals(node.getMarker().getName())) { for (INode child : node.getChildren()) { // 子项标记名称为前面定义的标记名称,如序号、姓名等 // System.out.print(child.getMarker().getName() + "="); System.out.print(child.getValue()); System.out.print("\t"); } System.out.println("_____________________________________"); } } ### 输出结果 1 张三 男 20 汉族 _____________________________________ 2 李四 女 18 汉族 _____________________________________ 3 王二 男 30 满族 _____________________________________ ### 生成文件示例 // 定义标记列表 List markers = new ArrayList(); // 标题只有一行,使用Marker,位于第0行第0列 Marker markerHead = new Marker("标题", 0, 0); // 设置宽度为2列 markerHead.setWidth(2); // 添加需要取的标题标记及位于父区域内的坐标 markerHead.addChild(new Marker("sn", 0, 0)); markerHead.addChild(new Marker("name", 0, 1)); // 数据区域为重复性数据,使用RepeatedMarker,位于第1行第0列 Marker markerBody = new RepeatedMarker("数据", 1, 0); // 设置宽度为2列 markerBody.setWidth(2); // 添加需要取的数据标记及位于父区域内的坐标 markerBody.addChild(new Marker("序号", 0, 0)); markerBody.addChild(new Marker("姓名", 0, 1)); // 添加标记 markers.add(markerHead); markers.add(markerBody); // 通过工厂获取xls解析接口 IParser parser = ParserFactory.getParser("xls"); // 获取节点写入接口 INodeWriter writer = parser.write(markers); // 写标题 Node head = new Node("标题"); head.addChild(new Node("sn", "序号")); head.addChild(new Node("name", "姓名")); writer.add(head); // 写数据 Node body = new Node("数据"); body.addChild(new Node("序号", "1")); body.addChild(new Node("姓名", "张三")); writer.add(body); // 再写一行数据 body = new Node("数据"); body.addChild(new Node("序号", "2")); body.addChild(new Node("姓名", "李四")); writer.add(body); // 待生成文件 File file = new File("template.xls"); // 输出 writer.save(file); ## 解析机制 在一个表格中,指定横坐标、纵坐标、宽度(多少列),高度(多少行),你就能圈出一个区域。给这个区域贴上标签,你就能很容易的从表格中找到你感兴趣的内容,这个标签,也就是标记(Marker)。 标记可大可小,大到整个Sheet(当然这样没有实际意义),小到一个单元格。 标记支持层级,一个大的标记下,可以包含多个小的子标记(子标记的坐标以父标记为基准),这样就可以从大到小逐步锁定目标。 遍历读取的时候,仅遍历顶级的标记,子标记内容通过getChildren方法获取。 ### 单一标记 单一标记(Marker)为不重复出现的标记。 以下图为例,通过"姓名"标记可直接读取到"六特尔",通过"email"标记可直接读取到"6tail@6tail.cn",也可修改对应的值。 ![单一标记示例](https://github.com/6tail/dp2/raw/master/samples/dp2-0.png) ### 重复标记 重复标记(RepeatedMarker)为重复出现的标记。 以下图为例,每一行数据为一个大的标记(取名为"名单",按行重复出现,因不确定有多少行数据,因此重复标记的坐标以第一次出现的坐标为准),大标记中包含两个子标记("姓名"和"性别")。 ![重复标记示例](https://github.com/6tail/dp2/raw/master/samples/dp2-1.png) ### 组合标记 无论多复杂的表格,都可以拆分为单一标记与重复标记的组合,标记表格的方式也可以五花八门,你选择的标记方式将决定解析的效率。 ![复杂标记示例](https://github.com/6tail/dp2/raw/master/samples/dp2-2.png) 以上图这个表格为例,如果我们需要读取主题和名单,可定义两个顶级标记,"主题"标记位于行1列1,"名单"标记位于行4列1,宽2高3。 其中"名单"中包含多个重复标记"人员",位于行0列0,宽2高1。 "人员"标记又包含"姓名"标记(位于行0列0,宽1高1)和"性别"标记(位于行0列1,宽1高1)。 ## 注意 坐标均以父标记为基准,从0开始计。