├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── CHANGE_LOG.md ├── LICENSE.txt ├── README.md ├── cgit.bat ├── cgit.sh ├── doc ├── CHANGE_LOG.md ├── CI集成.md ├── bom │ └── README.md ├── issues │ ├── issues-01-collection.md │ ├── issues-02-embedded.md │ ├── issues-03-deadcycle.md │ ├── issues-04-config.md │ ├── issues-05-lts.md │ ├── v0.0.8-csv读取写入优化.md │ └── v0.0.9-csv写入优化文档优化.md ├── user │ ├── 01-csv-引导类.md │ ├── 02-csv-注解使用.md │ ├── 03-csv-支持集合类.md │ ├── 04-csv-支持内嵌对象.md │ ├── 05-csv-特殊字符转义.md │ └── CSV.md ├── 发布流程.md └── 版本迭代规范.md ├── pom.xml ├── release.bat ├── release.sh ├── release_rm.sh └── src ├── main ├── java │ └── com │ │ └── github │ │ └── houbb │ │ └── csv │ │ ├── annotation │ │ ├── Csv.java │ │ └── CsvEntry.java │ │ ├── api │ │ ├── ICodeDesc.java │ │ ├── ICsv.java │ │ ├── IReadContext.java │ │ ├── IReadConverter.java │ │ ├── IWriteContext.java │ │ └── IWriteConverter.java │ │ ├── bs │ │ ├── CsvReadBs.java │ │ └── CsvWriteBs.java │ │ ├── constant │ │ ├── CsvConfigConst.java │ │ ├── CsvConst.java │ │ ├── CsvEscapeConst.java │ │ ├── CsvOperateType.java │ │ └── package-info.java │ │ ├── exception │ │ └── CsvException.java │ │ ├── package-info.java │ │ ├── support │ │ ├── context │ │ │ ├── DefaultReadContext.java │ │ │ ├── DefaultWriteContext.java │ │ │ ├── SingleReadContext.java │ │ │ ├── SingleWriteContext.java │ │ │ └── package-info.java │ │ ├── convert │ │ │ ├── mapping │ │ │ │ ├── ReadMappingConverter.java │ │ │ │ └── WriteMappingConverter.java │ │ │ ├── package-info.java │ │ │ ├── read │ │ │ │ ├── AbstractCodeDescReadConverter.java │ │ │ │ ├── AbstractCodeDescWriteConverter.java │ │ │ │ ├── CommonReadConverter.java │ │ │ │ ├── collection │ │ │ │ │ ├── ArrayReadConverter.java │ │ │ │ │ ├── CollectionReadConverter.java │ │ │ │ │ └── MapReadConverter.java │ │ │ │ ├── entry │ │ │ │ │ └── EntryReadConverter.java │ │ │ │ ├── package-info.java │ │ │ │ └── type │ │ │ │ │ ├── ITypeConverter.java │ │ │ │ │ ├── impl │ │ │ │ │ ├── BooleanReadConverter.java │ │ │ │ │ ├── ByteReadConverter.java │ │ │ │ │ ├── CharacterReadConverter.java │ │ │ │ │ ├── DoubleReadConverter.java │ │ │ │ │ ├── FloatReadConverter.java │ │ │ │ │ ├── IntegerReadConverter.java │ │ │ │ │ ├── LongReadConverter.java │ │ │ │ │ ├── ShortReadConverter.java │ │ │ │ │ ├── StringReadConverter.java │ │ │ │ │ └── package-info.java │ │ │ │ │ └── package-info.java │ │ │ └── write │ │ │ │ ├── CommonWriteConverter.java │ │ │ │ ├── StringWriteConverter.java │ │ │ │ ├── collection │ │ │ │ ├── AbstractCollectionWriteConverter.java │ │ │ │ ├── ArrayWriteConverter.java │ │ │ │ ├── CollectionWriteConverter.java │ │ │ │ └── MapWriteConverter.java │ │ │ │ ├── entry │ │ │ │ └── EntryWriteConverter.java │ │ │ │ └── package-info.java │ │ ├── csv │ │ │ ├── DefaultCsv.java │ │ │ ├── DefaultStringListCsv.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── reader │ │ │ ├── ICsvReader.java │ │ │ ├── impl │ │ │ │ ├── CsvReaderFile.java │ │ │ │ ├── CsvReaderFilePath.java │ │ │ │ ├── CsvReaderInputStream.java │ │ │ │ ├── CsvReaderList.java │ │ │ │ └── CsvReaders.java │ │ │ └── package-info.java │ │ └── writer │ │ │ ├── ICsvWriter.java │ │ │ ├── ICsvWriterContext.java │ │ │ └── impl │ │ │ ├── CsvWriterConsole.java │ │ │ ├── CsvWriterContext.java │ │ │ ├── CsvWriterFilePath.java │ │ │ ├── CsvWriterNone.java │ │ │ └── CsvWriters.java │ │ └── util │ │ ├── CsvBomUtil.java │ │ ├── CsvFieldUtil.java │ │ ├── CsvHelper.java │ │ ├── CsvInnerUtil.java │ │ └── CsvStringListHelper.java └── resources │ └── readme.txt └── test ├── java └── com │ └── github │ └── houbb │ └── csv │ ├── bs │ ├── CsvReadBsTest.java │ ├── CsvWriteBsTest.java │ └── package-info.java │ ├── convert │ ├── ReadDateConvert.java │ ├── WriteDateConvert.java │ └── WriteStatusEnumConvert.java │ ├── enums │ └── StatusEnum.java │ ├── model │ ├── User.java │ ├── UserAnnotation.java │ ├── UserCollection.java │ ├── UserEntry.java │ ├── UserEscape.java │ ├── UserMapping.java │ ├── UserSelfRef.java │ ├── UserType.java │ └── UserWithSerialId.java │ └── util │ ├── CsvHelperReaderTest.java │ ├── CsvHelperWriterTest.java │ ├── CsvStringListHelperTest.java │ └── SplitTest.java └── resources ├── annotation.csv ├── collection.csv ├── common.csv ├── common_id.csv ├── entry.csv ├── escape.csv ├── helper.csv ├── mapping.csv ├── selfRef.csv ├── stringlist.csv └── stringlist2.csv /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | *.war 5 | *.zip 6 | *.tar 7 | *.tar.gz 8 | 9 | # eclipse ignore 10 | .settings/ 11 | .project 12 | .classpath 13 | 14 | # idea ignore 15 | .idea/ 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # temp ignore 21 | *.log 22 | *.cache 23 | *.diff 24 | *.patch 25 | *.tmp 26 | *.java~ 27 | *.properties~ 28 | *.xml~ 29 | 30 | # system ignore 31 | .DS_Store 32 | Thumbs.db 33 | 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - openjdk8 4 | install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true 5 | script: mvn test 6 | after_success: 7 | - mvn clean cobertura:cobertura coveralls:report 8 | 9 | -------------------------------------------------------------------------------- /CHANGE_LOG.md: -------------------------------------------------------------------------------- 1 | # 变更日志 2 | 3 | | 类型 | 说明 | 4 | |:----|:----| 5 | | A | 新增 | 6 | | U | 更新 | 7 | | D | 删除 | 8 | | T | 测试 | 9 | | O | 优化 | 10 | | F | 修复BUG | 11 | 12 | # release_0.0.1 13 | 14 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 15 | |:---|:---|:---|:---|:--| 16 | | 1 | A | 基本功能的实现 | 2019-6-1 13:55:32 | | 17 | 18 | # release_0.0.2 19 | 20 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 21 | |:---|:---|:---|:---|:--| 22 | | 1 | O | 注解相关测试用例的完善 | 2019-6-10 13:55:32 | | 23 | 24 | # release_0.0.3 25 | 26 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 27 | |:---|:---|:---|:---|:--| 28 | | 1 | A | 支持集合、数组、Map 等常见集合 | 2019-6-17 19:42:30 | | 29 | 30 | # release_0.0.4 31 | 32 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 33 | |:---|:---|:---|:---|:--| 34 | | 1 | O | 优化 head/bom 信息的写入 | 2019-6-18 20:32:36 | | 35 | | 2 | O | 优化读写的实现方式,便于后期拓展 | 2019-6-18 20:32:36 | | 36 | | 3 | O | 添加缓存,提升性能 | 2019-6-18 20:32:36 | | 37 | 38 | # release_0.0.5 39 | 40 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 41 | |:---|:---|:---|:---|:--| 42 | | 1 | A | 支持内嵌对象 | 2019-6-20 11:18:14 | | 43 | 44 | # release_0.0.6 45 | 46 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 47 | |:---|:---|:---|:---|:--| 48 | | 1 | A | 支持特殊字符的转义 | 2019-6-20 17:23:30 | | 49 | 50 | # release_0.0.7 51 | 52 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 53 | |:---|:---|:---|:---|:--| 54 | | 1 | F | 修复文件生成序列化标识问题 | 2020-2-10 09:36:32 | | 55 | 56 | # release_0.0.8 57 | 58 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 59 | |:---|:---|:---|:---|:--| 60 | | 1 | A | 支持各种信息读取的新方式 | 2020-3-23 16:44:27 | | 61 | | 2 | A | 新增 CsvHelper,为操作提供便利性。 | 2020-3-23 16:44:27 | | 62 | | 3 | O | CsvReaderBs 引导类优化,便于后期调整 | 2020-3-23 16:44:27 | | 63 | 64 | # release_0.0.9 65 | 66 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 67 | |:---|:---|:---|:---|:--| 68 | | 1 | A | 支持文件写入为 APPEND 模式 | 2020-10-26 23:59:34 | | 69 | 70 | # release_0.1.0 71 | 72 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 73 | |:---|:---|:---|:---|:--| 74 | | 1 | A | 新增枚举值映射处理 | 2020-10-26 23:59:34 | | 75 | 76 | # release_0.2.0 77 | 78 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 79 | |:---|:---|:------------------|:--------------------|:--| 80 | | 1 | A | 单行的操作=>stringList | 2023-11-28 23:59:34 | | 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # csv 2 | 3 | [CSV](https://github.com/houbb/csv) 是基于 java 注解的 csv 读写框架,让你更加优雅方便的操作 csv。 4 | 5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.houbb/csv/badge.svg)](http://mvnrepository.com/artifact/com.github.houbb/csv) 6 | [![Build Status](https://www.travis-ci.org/houbb/csv.svg?branch=master)](https://www.travis-ci.org/houbb/csv?branch=master) 7 | [![](https://img.shields.io/badge/license-Apache2-FF0080.svg)](https://github.com/houbb/csv/blob/master/LICENSE.txt) 8 | [![Open Source Love](https://badges.frapsoft.com/os/v2/open-source.svg?v=103)](https://github.com/houbb/csv) 9 | 10 | ## 相关框架 11 | 12 | [Apache commons-csv](https://github.com/apache/commons-csv) 13 | 14 | [super-csv](https://github.com/super-csv/super-csv) 15 | 16 | 简单看了下,这两个框架提供的特性都非常的基础。 17 | 18 | ## 创作原由 19 | 20 | 以前觉得 csv 文件的读写非常简单,就懒得封装。 21 | 22 | 最近一个月写了两次 csv 文件相关的东西,发现要处理的细节还是有的,还浪费比较多的时间。 23 | 24 | 比如: 25 | 26 | 1. UTF-8 中文编码使用 excel 打开乱码,因为缺少 BOM 头。 27 | 28 | 2. 不同类型字段转化为字符串,顺序的指定,head 头的指定,如果手写都会很繁琐。 29 | 30 | 3. 读取的时候最后 `,` 后无元素,split 会缺失等。 31 | 32 | 为了解决上述问题,此框架应运而生。 33 | 34 | ## 特性 35 | 36 | - Fluent 流式写法 37 | 38 | - 基于 java 注解,支持自定义的转换和灵活配置 39 | 40 | - 内置 8 大基本类型以及 String 类型转换 41 | 42 | - 解决 Excel 直接打开,utf-8 乱码问题 43 | 44 | - 支持集合、数组、Map 的存取 45 | 46 | - 支持对象中内嵌其他对象 47 | 48 | - 支持特殊字符转义 49 | 50 | ### v0.1.0 变更 51 | 52 | - 枚举值映射 53 | 54 | 支持快速简单的枚举值映射 55 | 56 | # 快速开始 57 | 58 | ## 环境 59 | 60 | jdk7+ 61 | 62 | maven 3.x 63 | 64 | ## maven 引入 65 | 66 | ```xml 67 | 68 | com.github.houbb 69 | csv 70 | 0.2.0 71 | 72 | ``` 73 | 74 | ## 朴素的读写 75 | 76 | 直接转换为 string list. 77 | 78 | ```java 79 | final String path = "stringlist.csv"; 80 | final String target = "stringlist2.csv"; 81 | 82 | List> dataList = CsvStringListHelper.read(path); 83 | System.out.println(dataList); 84 | 85 | CsvStringListHelper.write(target, dataList); 86 | ``` 87 | 88 | - stringlist.csv 89 | 90 | ```csv 91 | id,name,age 92 | 1,"user,1",10 93 | 2,"user,1",201 94 | ``` 95 | 96 | - dataList 字符串列表 97 | 98 | ``` 99 | [[id, name, age], [1, user,1, 10], [2, user,1, 201]] 100 | ``` 101 | 102 | ## 示例代码 103 | 104 | ### 写入 105 | 106 | 详情参考 [CsvHelperWriterTest.java](https://github.com/houbb/csv/blob/release_0.0.8/src/test/java/com/github/houbb/csv/util/CsvHelperWriterTest.java) 107 | 108 | ```java 109 | final String path = "src\\test\\resources\\helper.csv"; 110 | 111 | CsvHelper.write(buildCommonList(), CsvWriters.filePath(path)); 112 | ``` 113 | 114 | - 文件生成 115 | 116 | ```csv 117 | name,age,score,money,sex,level,id,status,coin 118 | 你好,10,60.0,200.0,true,4,1,Y,1 119 | ``` 120 | 121 | ### 读取 122 | 123 | 详情参考 [CsvHelperReaderTest.java](https://github.com/houbb/csv/blob/release_0.0.8/src/test/java/com/github/houbb/csv/util/CsvHelperReaderTest.java) 124 | 125 | - 读取文件 126 | 127 | ```java 128 | final String path = "src\\test\\resources\\common.csv"; 129 | 130 | List userList = CsvHelper.read(path, User.class); 131 | Assert.assertEquals("[User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}]", userList.toString()); 132 | ``` 133 | 134 | - 读取字符串列表 135 | 136 | 也支持直接读取字符串列表。 137 | 138 | ```java 139 | List lines = Arrays.asList("name,age,score,money,sex,level,id,status,coin", 140 | "你好,10,60.0,200.0,true,4,1,Y,1"); 141 | 142 | List userList = CsvHelper.read(lines, User.class); 143 | Assert.assertEquals("[User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}]", userList.toString()); 144 | ``` 145 | 146 | ### 对象信息 147 | 148 | 其中使用的属性如下: 149 | 150 | - User.java 151 | 152 | 演示基本类型的转换 153 | 154 | ```java 155 | public class User { 156 | 157 | private String name; 158 | 159 | private int age; 160 | 161 | private float score; 162 | 163 | private double money; 164 | 165 | private boolean sex; 166 | 167 | private short level; 168 | 169 | private long id; 170 | 171 | private char status; 172 | 173 | private byte coin; 174 | 175 | //Getter & Setter & toString() 176 | } 177 | ``` 178 | 179 | - 对象列表构建 180 | 181 | ```java 182 | /** 183 | * 构建通用测试列表 184 | * @return 列表 185 | */ 186 | private List buildCommonList() { 187 | User user = new User(); 188 | short s = 4; 189 | byte b = 1; 190 | user.age(10) 191 | .name("你好") 192 | .id(1L) 193 | .score(60) 194 | .coin(b) 195 | .level(s) 196 | .money(200) 197 | .sex(true) 198 | .status('Y'); 199 | return Arrays.asList(user); 200 | } 201 | ``` 202 | 203 | # 拓展阅读 204 | 205 | [01-CSV 引导类方法说明](doc/user/01-csv-引导类.md) 206 | 207 | [02-CSV 字段注解的使用](doc/user/02-csv-注解使用.md) 208 | 209 | [03-CSV 集合相关支持](doc/user/03-csv-支持集合类.md) 210 | 211 | [04-CSV 内嵌对象使用](doc/user/04-csv-支持内嵌对象.md) 212 | 213 | [05-CSV 内嵌对象使用](doc/user/05-csv-特殊字符转义.md) 214 | 215 | # 后期 road-map 216 | 217 | - 引入 `@Order` 注解或者新增 `order()` 注解属性 218 | 219 | 避免 java 反射存在的字段顺序和声明顺序不一致问题 220 | 221 | - 使用 converter 项目统一优化 222 | 223 | 读写转换等操作统一复用。 -------------------------------------------------------------------------------- /cgit.bat: -------------------------------------------------------------------------------- 1 | :: 用于提交当前变更(windows) 2 | :: author: houbb 3 | :: LastUpdateTime: 2018-11-22 09:08:52 4 | :: 用法:双击运行,或者当前路径 cmd 直接输入 .\cgit.bat 5 | 6 | git pull 7 | git add . 8 | git commit -m "[Feature] add for new" 9 | git push 10 | git status 11 | 12 | -------------------------------------------------------------------------------- /cgit.sh: -------------------------------------------------------------------------------- 1 | # 提交 2 | 3 | git pull 4 | git add . 5 | git commit -m "[Feature] add for new" 6 | git push 7 | git status 8 | 9 | # 1. 赋值权限: chmod +x ./cgit.sh 10 | # 2. 执行: ./cgit.sh 11 | # Last Update Time: 2018-11-21 21:55:38 12 | # Author: houbb -------------------------------------------------------------------------------- /doc/CHANGE_LOG.md: -------------------------------------------------------------------------------- 1 | # 变更日志 2 | 3 | | 类型 | 说明 | 4 | |:----|:----| 5 | | A | 新增 | 6 | | U | 更新 | 7 | | D | 删除 | 8 | | T | 测试 | 9 | | O | 优化 | 10 | | F | 修复BUG | 11 | 12 | # release_0.0.1 13 | 14 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 15 | |:---|:---|:---|:---|:--| 16 | | 1 | A | 基本功能的实现 | 2019-6-1 13:55:32 | | 17 | 18 | # release_0.0.2 19 | 20 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 21 | |:---|:---|:---|:---|:--| 22 | | 1 | O | 注解相关测试用例的完善 | 2019-6-10 13:55:32 | | 23 | 24 | # release_0.0.3 25 | 26 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 27 | |:---|:---|:---|:---|:--| 28 | | 1 | A | 支持集合、数组、Map 等常见集合 | 2019-6-17 19:42:30 | | 29 | 30 | # release_0.0.4 31 | 32 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 33 | |:---|:---|:---|:---|:--| 34 | | 1 | O | 优化 head/bom 信息的写入 | 2019-6-18 20:32:36 | | 35 | | 2 | O | 优化读写的实现方式,便于后期拓展 | 2019-6-18 20:32:36 | | 36 | | 3 | O | 添加缓存,提升性能 | 2019-6-18 20:32:36 | | 37 | 38 | # release_0.0.5 39 | 40 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 41 | |:---|:---|:---|:---|:--| 42 | | 1 | A | 支持内嵌对象 | 2019-6-20 11:18:14 | | 43 | 44 | # release_0.0.6 45 | 46 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 47 | |:---|:---|:---|:---|:--| 48 | | 1 | A | 支持特殊字符的转义 | 2019-6-20 17:23:30 | | 49 | 50 | # release_0.0.7 51 | 52 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 53 | |:---|:---|:---|:---|:--| 54 | | 1 | F | 修复文件生成序列化标识问题 | 2020-2-10 09:36:32 | | 55 | 56 | # release_0.0.8 57 | 58 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 59 | |:---|:---|:---|:---|:--| 60 | | 1 | A | 支持各种信息读取的新方式 | 2020-3-23 16:44:27 | | 61 | | 2 | A | 新增 CsvHelper,为操作提供便利性。 | 2020-3-23 16:44:27 | | 62 | | 3 | O | CsvReaderBs 引导类优化,便于后期调整 | 2020-3-23 16:44:27 | | -------------------------------------------------------------------------------- /doc/CI集成.md: -------------------------------------------------------------------------------- 1 | # 文档说明 2 | 3 | 作者:侯宾宾 4 | 5 | 时间:2018-04-24 10:11:43 6 | 7 | 说明:如何进行项目的持续集成+测试覆盖率 8 | 9 | # Travis-CI 10 | 11 | [https://www.travis-ci.org](https://www.travis-ci.org) 直接添加此项目 12 | 13 | # Coveralls 14 | 15 | - 添加项目 16 | 17 | [https://coveralls.io/repos/new](https://coveralls.io/repos/new) 直接添加项目 18 | 19 | - 生成密匙 20 | 21 | ``` 22 | travis encrypt COVERALLS_TOKEN=${your_repo_token} 23 | ``` 24 | 25 | - 添加到文件 26 | 27 | ``` 28 | travis encrypt COVERALLS_TOKEN=${your_repo_token} --add 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /doc/bom/README.md: -------------------------------------------------------------------------------- 1 | # BOM 2 | 3 | —— Byte Order Mark,中文名译作“字节顺序标记”。 4 | 5 | 在这里找到一段关于 BOM 的说明: 6 | 7 | 在UCS 编码中有一个叫做 "Zero Width No-Break Space" ,中文译名作“零宽无间断间隔”的字符,它的编码是 FEFF。 8 | 9 | 而 FFFE 在 UCS 中是不存在的字符,所以不应该出现在实际传输中。 10 | 11 | UCS 规范建议我们在传输字节流前,先传输字符 "Zero Width No-Break Space"。 12 | 13 | 这样如果接收者收到 FEFF,就表明这个字节流是 Big-Endian 的;如果收到FFFE,就表明这个字节流是 Little- Endian 的。因此字符 "Zero Width No-Break Space" (“零宽无间断间隔”)又被称作 BOM。 14 | 15 | UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。 16 | 17 | 字符 "Zero Width No-Break Space" 的 UTF-8 编码是 EF BB BF。 18 | 19 | 所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8编码了。 20 | 21 | Windows 就是使用 BOM 来标记文本文件的编码方式的。 22 | 23 | 字符U+FEFF如果出现在字节流的开头,则用来标识该字节流的字节序,是高位在前还是低位在前。 24 | 25 | 如果它出现在字节流的中间,则表达零宽度非换行空格的意义,用户看起来就是一个空格。 26 | 27 | 从Unicode3.2开始,U+FEFF只能出现在字节流的开头,只能用于标识字节序,就如它的名称——字节序标记——所表示的一样;除此以外的用法已被舍弃。取而代之的是,使用U+2060来表达零宽度无断空白。 28 | 29 | 类似WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。 30 | 31 | 它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。 32 | 33 | 对于一般的文件,这样并不会产生什么麻烦。 34 | 35 | 但对于 PHP来说,BOM是个大麻烦。 36 | 37 | PHP并不会忽略BOM,所以在读取、包含或者引用这些文件时,会把BOM作为该文件开头正文的一部分。 38 | 39 | 根据嵌入式语言的特点,这串字符将被直接执行(显示)出来。 40 | 41 | 由此造成即使页面的 top padding 设置为0,也无法让整个网页紧贴浏览器顶部,因为在html一开头有这3个字符呢! 42 | 43 | 44 | # 不同编码的对应 bom 45 | 46 | ``` 47 | 48 | ``` 49 | 50 | # 参考资料 51 | 52 | [中文乱码详解](https://www.cnblogs.com/lzmrex/p/9832086.html) 53 | 54 | [大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题](https://blog.csdn.net/ztsinghua/article/details/44277833) 55 | 56 | [常见编码和编码头BOM](https://www.cnblogs.com/signheart/p/c3b1000186199e89d4e02c33f39ed418.html) -------------------------------------------------------------------------------- /doc/issues/issues-01-collection.md: -------------------------------------------------------------------------------- 1 | # 基本的 features 实现 2 | 3 | # Iterable 的支持 4 | 5 | ## list 6 | 7 | ## array 8 | 9 | ## map 10 | 11 | 是否可以如下存储:(如果 toString() 无法实现反序列化的话) 12 | 13 | 规范:保证和 csv 用逗号分隔的统一性 14 | 15 | 列表(可遍历对象):`|` 分隔开 16 | 17 | map: k:v | k2:v2 | 18 | 19 | ## 实现方式 20 | 21 | 如果可以根据 toString() 反序列,直接添加反解析即可。 22 | 23 | # 对于内嵌对象 24 | 25 | 不推荐存储在一个文件中。 26 | 27 | 如果存储在多个文件中,建议存储如下: 28 | 29 | ## 默认策略 30 | 31 | `XXX-embedded-fieldsName.csv` 用来和原始的 XXX CSV 文件对应。 32 | 33 | 类似于数据库中的主从表的概念。 34 | 35 | ## 关联关系 36 | 37 | 使用主信息中的行号,作为从数据的关联标识。默认放在第一列。 38 | 39 | ## 支持自定义 40 | 41 | 自定义嵌套的数据信息存储文件。 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /doc/issues/issues-02-embedded.md: -------------------------------------------------------------------------------- 1 | # 嵌套对象的处理 2 | 3 | 如果想实现嵌套对象的持久化,而又不借助 JSON 序列化。 4 | 5 | 同时保证 `,` 号分隔。 6 | 7 | 应该怎么做呢? 8 | 9 | ## 类似于表的关系 10 | 11 | 为了保证 csv 用逗号分隔的统一性,可以新建一个文件。(类似于主从表) 12 | 13 | 核心对象: 14 | 15 | ```java 16 | User { 17 | Address address; 18 | } 19 | ``` 20 | 21 | 其中内嵌了一个 address 对象。 22 | 23 | 如果 User 对象信息存储在 `user.csv` 中。 24 | 25 | 嵌套的对象可以默认存储在 `user.address.csv` 文件中。 26 | 27 | ## 对象类型 28 | 29 | 单个对象:只存储一条 30 | 31 | 集合/数组:存储多条 32 | 33 | Map 对象:暂时不支持。(过于麻烦) 34 | 35 | ## 如何声明 36 | 37 | 为了避免无意义的递归处理,可以使用注解 `@Embedded` 显示指定。 38 | 39 | 这个注解和 `@Csv` 注解可以同时使用吗? 40 | 41 | # @Embedded 应该是独立的注解吗? 42 | 43 | ## 独立 44 | 45 | ## 不独立 46 | 47 | 不独立,放在那里? 48 | 49 | (1)默认根据类型处理 50 | 51 | 缺点:不好,无法感知用户意图。 52 | 53 | (2)csv 注解添加一个属性 54 | 55 | `embedded=false` 是否进行嵌套的处理,默认为 false。 56 | 57 | 优点:可以感知用户意图 58 | 59 | ## 独立 60 | 61 | 全新的一个注解 62 | 63 | 问题:如何解析?是否会和 csv 注解冲突? 64 | 65 | 解析方式: 66 | 67 | (1)csv 和原来一样,如果同时声明 `@embedded`。则进行相关处理。 68 | 69 | (2)会和原来的处理有冲突吗? 70 | 71 | 也可以没有冲突。 72 | 73 | 如果是普通的,未声明 embedded,则直接根据 toString(); 74 | 75 | 如果声明了 embedded,则储存信息变为拓展【文件对应的行号】。 76 | 77 | 注意:不支持多层嵌套,最多一层。(后期再进行拓展处理) 78 | 79 | 或者支持多级嵌套: 80 | 81 | `A.b.c.csv` 这种命名方式。 82 | 83 | # 无效的声明 84 | 85 | 如果指定的属性不是对象,则忽略当前注解 `@embedded`。 86 | 87 | # 最终的方案 88 | 89 | (1)因为 embedded 和 csv 的解析息息相关。所以直接当做一个属性 90 | 91 | (2)默认为 false 92 | 93 | (3)只有当指定的属性为对象,或者为对象的集合时,且 embedded=true。才会生效。 94 | 95 | ## 存储的方式 96 | 97 | 根据链式调用 98 | 99 | 存储在 `a.b.csv` 100 | 101 | 原始文件 `a.csv` 存储 a.b.csv 文件中存储行号。 102 | 103 | 以后更多层的嵌套,也保持这一规范。 104 | 105 | 列表多个之间用 `|` 隔开,比如: 106 | 107 | `1|2|3` 108 | 109 | ## slice 方式的存储 110 | 111 | 如果行数过多,比如 1-10 行。直接存储: 112 | 113 | ``` 114 | 1|2|3|4|5|6|7|8|9|10 115 | ``` 116 | 117 | 显然有点傻傻的。不如参考 slice 的设计,存储为: 118 | 119 | ``` 120 | 1:10 121 | ``` 122 | 123 | 当然这样的缺点,引入了新的符号:`:` 124 | 125 | 为了和原来兼容,可以考虑存储 `1|10` 前面的是开始,后面的是结束。 126 | 127 | 如果只有一行:直接存储为 `1` 或者 `1|1` 也不影响解析。 128 | 129 | ## 解析 130 | 131 | 说好了存储,剩下的就是解析。 132 | 133 | 解析正常和原来一样。 134 | 135 | 如果发现一个字段是对象(对象列表)+指定了 embedded=true 136 | 137 | 则进行相关的关联查看: 138 | 139 | (1)文件的路径:当前文件路径+属性.csv 文件 140 | 141 | (2)文件对应的行信息:根据存储的内容比如 `1|3` 或者 `2` 直接获取对应文件的内容。 142 | 143 | (3)根据获取的文件信息,构建嵌套的对象信息。 144 | 145 | # 性能的考虑 146 | 147 | 如果内容较多,采用 list 行号存储,则性能较差。 148 | 149 | 可以考虑存储文件的开始/结束位置。 150 | 151 | 使用 RandomFileAccess 来进行文件的读取。 152 | 153 | 问题:如果换行?(直接封装在 util 工具类中) 154 | 155 | -------------------------------------------------------------------------------- /doc/issues/issues-03-deadcycle.md: -------------------------------------------------------------------------------- 1 | # 如果一个类引用本身 2 | 3 | ```java 4 | class User { 5 | List children; 6 | } 7 | ``` 8 | 9 | 很可能会导致死循环。 10 | 11 | Done:没有这个问题。 12 | 13 | 验证并修复这个问题。 14 | 15 | # 对于特殊符号的转义。 16 | 17 | 最好在 @since 0.0.6 版本。 18 | 19 | # 更多的特性支持-持续更新特性 20 | 21 | 更多的 java 类型的内置支持。 -------------------------------------------------------------------------------- /doc/issues/issues-04-config.md: -------------------------------------------------------------------------------- 1 | # 灵活的配置 2 | 3 | ## 对于转义后字符的配置 4 | 5 | ## 对于 -------------------------------------------------------------------------------- /doc/issues/issues-05-lts.md: -------------------------------------------------------------------------------- 1 | # 更加丰富的内置支持 2 | 3 | 更多类型。 4 | 5 | BigInteger 6 | 7 | -------------------------------------------------------------------------------- /doc/issues/v0.0.8-csv读取写入优化.md: -------------------------------------------------------------------------------- 1 | # 单行字符串 2 | 3 | 单行字符串直接转换为单个对象。 4 | 5 | List 直接转换为对象列表. -------------------------------------------------------------------------------- /doc/issues/v0.0.9-csv写入优化文档优化.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/csv/b8c10e492545b43ad5f192fd99b2de417bc3ebfa/doc/issues/v0.0.9-csv写入优化文档优化.md -------------------------------------------------------------------------------- /doc/user/01-csv-引导类.md: -------------------------------------------------------------------------------- 1 | # CsvBs-csv 引导类 2 | 3 | 为了用户使用的便利性,和后期拓展的灵活性。 4 | 5 | ## 引导类 6 | 7 | CSV 有两个引导类: 8 | 9 | | 名称 | 作用 | 10 | |:---|:---| 11 | | CsvWriteBs | csv 文件写入引导类 | 12 | | CsvReadBs | csv 文件读取引导类 | 13 | 14 | ## CsvWriteBs 15 | 16 | | 方法 | 默认值 | 说明 | 17 | |:---|:---|:---| 18 | | newInstance(final String path) | `必填` | 创建实例,并且指定待写入文件路径。| 19 | | path (final String path) | | 配置文件路径,只有重新指定 path 路径时需要调用。| 20 | | writeHead(boolean writeBom) | `true` |是否写入 head 头,如果想指定名称,可以结合注解。只有无 head 信息时,会写入。 | 21 | | writeBom(boolean writeBom) | `true` | 是否写入 UTF8 BOM 头,只有文件为空时才会写入。 | 22 | | charset(String charset) | `UTF-8` | 指定文件编码 | 23 | | sort(ISort sort) | NoSort | 默认不进行字段排序 | 24 | | write(List list) | `无` | 待写入的文件列表 | 25 | | escape | false | 是否进行特殊字符的转换 | 26 | 27 | ## CsvReadBs 28 | 29 | | 方法 | 默认值 | 说明 | 30 | |:---|:---|:---| 31 | | newInstance(final String path) | `必填` |创建实例,并且指定待读取文件路径。| 32 | | path (final String path) | | 配置文件路径,只有重新指定 path 路径时需要调用。| 33 | | charset(String charset) | `UTF-8` | 指定文件编码 | 34 | | sort(ISort sort) | NoSort | 默认不进行字段排序 | 35 | | startIndex(int startIndex) | 1 | 文件的第二行,默认第一行是 head | 36 | | endIndex(int endIndex) | | 文件的最后一行 | 37 | | escape | false | 是否进行特殊字符的转换 | 38 | -------------------------------------------------------------------------------- /doc/user/02-csv-注解使用.md: -------------------------------------------------------------------------------- 1 | # Csv 注解 2 | 3 | ## 注解属性说明 4 | 5 | 用于待处理对象的字段上。 6 | 7 | ```java 8 | /** 9 | * 字段显示名称 10 | * 1. 默认使用 field.name 11 | * @return 显示名称 12 | */ 13 | String label() default ""; 14 | 15 | /** 16 | * 读取是否需要 17 | * @return 是 18 | */ 19 | boolean readRequire() default true; 20 | 21 | /** 22 | * 写入是否需要 23 | * @return 是 24 | */ 25 | boolean writeRequire() default true; 26 | 27 | /** 28 | * 读取转换 29 | * @return 处理实现类 30 | */ 31 | Class readConverter() default CommonReadConverter.class; 32 | 33 | /** 34 | * 写入转换 35 | * @return 处理实现类 36 | */ 37 | Class writeConverter() default StringWriteConverter.class; 38 | 39 | /** 40 | * 读映射 41 | * 42 | * S:成功;F:失败 43 | * 枚举值用 ; 分割,映射用 : 分割。 44 | * 45 | * 优先级:相比较 readConverter 优先使用 readMapping,如果值不为空,且当前字段的值为 String,才进行处理。否则忽略。 46 | * 注意:必须要有 : 分割符号,否则报错。只对 String 类型字段生效。 47 | * @return 读 48 | * @since 0.1.0 49 | */ 50 | String readMapping() default ""; 51 | 52 | /** 53 | * 写映射 54 | * 55 | * 优先级:相比较 writeConverter 优先使用 writeMapping,如果值不为空,且当前字段的值为 String,才进行处理。否则忽略。 56 | * 注意:必须要有 : 分割符号,否则报错。只对 String 类型字段生效。 57 | * @return 映射结果 58 | * @since 0.1.0 59 | */ 60 | String writeMapping() default ""; 61 | ``` 62 | 63 | ## 属性概览表 64 | 65 | | 属性 | 默认值 | 说明 | 66 | |:---|:---|:---| 67 | | label | 字段名称 | 用于 csv 头生成 | 68 | | readRequire | true | 是否需要从 csv 文件读取 | 69 | | writeRequire | true | 当前字段是否需要写入 csv 文件 | 70 | | readConverter | CommonReadConverter | 将 csv 中的字符串转化为当前字段类型,支持 8 大基本类型+String | 71 | | writeConverter | StringWriteConverter | 直接调用当前字段值 toString() 方法,null 直接为空字符串 | 72 | | readMapping | "" | 读取时的枚举值映射 | 73 | | writeMapping | "" | 写入时的枚举值映射 | 74 | 75 | 其中 readConverter/writeConverter 支持用户自定义 76 | 77 | 78 | # 使用代码示例 79 | 80 | ## 对象定义 81 | 82 | ```java 83 | public class UserAnnotation { 84 | 85 | @Csv(label = "名称") 86 | private String name; 87 | 88 | @Csv(label = "密码", readRequire = false, writeRequire = false) 89 | private String password; 90 | 91 | @Csv(label = "生日", readConverter = ReadDateConvert.class, writeConverter = WriteDateConvert.class) 92 | private Date birthday; 93 | 94 | //Getter & Setter & toString() 95 | } 96 | ``` 97 | 98 | 99 | ### ReadDateConvert/WriteDateConvert 100 | 101 | 使我们自定义的针对 Date 的转换实现。 102 | 103 | - Write 104 | 105 | ```java 106 | public class WriteDateConvert implements IWriteConverter { 107 | 108 | @Override 109 | public String convert(Date value) { 110 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); 111 | return dateFormat.format(value); 112 | } 113 | 114 | } 115 | ``` 116 | 117 | - ReadDateConvert 118 | 119 | ```java 120 | public class ReadDateConvert implements IReadConverter { 121 | 122 | @Override 123 | public Date convert(String value, Class fieldType) { 124 | try { 125 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); 126 | return dateFormat.parse(value); 127 | } catch (ParseException e) { 128 | throw new RuntimeException(e); 129 | } 130 | } 131 | 132 | } 133 | ``` 134 | 135 | ## 写入文件 136 | 137 | ```java 138 | public void annotationTest() { 139 | final String path = "src\\test\\resources\\annotation.csv"; 140 | CsvWriteBs.newInstance(path) 141 | .write(buildAnnotationList()); 142 | } 143 | ``` 144 | 145 | 其中列表构建: 146 | 147 | ```java 148 | /** 149 | * 构建基于注解的测试列表 150 | * @return 列表 151 | */ 152 | private List buildAnnotationList() { 153 | UserAnnotation user = new UserAnnotation(); 154 | user.name("你好") 155 | .password("123") 156 | .birthday(new Date()); 157 | return Arrays.asList(user); 158 | } 159 | ``` 160 | 161 | - 生成文件内容 162 | 163 | ``` 164 | 名称,生日 165 | 你好,20190603 166 | ``` 167 | 168 | ## 读取文件测试 169 | 170 | ```java 171 | public void annotationTest() { 172 | final String path = "src\\test\\resources\\annotation.csv"; 173 | List userList = CsvReadBs.newInstance(path) 174 | .read(UserAnnotation.class); 175 | System.out.println(userList); 176 | } 177 | ``` 178 | 179 | - 日志信息 180 | 181 | ``` 182 | [UserAnnotation{name='你好', password='null', birthday=Mon Jun 03 00:00:00 CST 2019}] 183 | ``` 184 | 185 | # 枚举映射 186 | 187 | ## 对象定义 188 | 189 | ```java 190 | public class UserMapping { 191 | 192 | @Csv(readMapping = "S:成功;F:失败", writeMapping = "S:成功;F:失败") 193 | private String status; 194 | 195 | //getter/setter/toString() 196 | 197 | } 198 | ``` 199 | 200 | 这种方法适合快速的枚举导出,如果比较复杂,可以使用对应的 converter 即可。 201 | 202 | ## 写入 203 | 204 | ```java 205 | UserMapping userMapping = new UserMapping(); 206 | userMapping.status("S"); 207 | 208 | CsvHelper.write(Collections.singletonList(userMapping), CsvWriters.filePath("src\\test\\resources\\mapping.csv")); 209 | ``` 210 | 211 | 输出文件效果 212 | 213 | ``` 214 | status 215 | 成功 216 | ``` 217 | 218 | 枚举值 S 被映射成了成功。 219 | 220 | ## 读取 221 | 222 | 有写入,就有对应的读取。 223 | 224 | ```java 225 | final String path = "src\\test\\resources\\mapping.csv"; 226 | 227 | List userList = CsvHelper.read(path, UserMapping.class); 228 | Assert.assertEquals("[UserMapping{status='S'}]", userList.toString()); 229 | ``` 230 | 231 | 可以把成功映射为 S,便于一些枚举值的映射处理和存储。 232 | -------------------------------------------------------------------------------- /doc/user/03-csv-支持集合类.md: -------------------------------------------------------------------------------- 1 | # 集合类 2 | 3 | 有时候对象中会包含数组、Map、Collection 等常见集合。 4 | 5 | 为了存储的便利性,默认提供集合的相关支持。 6 | 7 | 特性和普通字段保持一致,如果指定注解转换,则以注解为准。 8 | 9 | ## 使用示例 10 | 11 | - UserCollection.java 12 | 13 | 用于演示集合的对象 14 | 15 | ```java 16 | public class UserCollection { 17 | 18 | private String[] arrays; 19 | 20 | private LinkedList lists; 21 | 22 | private Map maps; 23 | 24 | private Set sets; 25 | 26 | //Getter/Setter/toString() 27 | } 28 | ``` 29 | 30 | ## 存储 31 | 32 | - 待存储对象的构建 33 | 34 | ```java 35 | /** 36 | * 构建基于集合的测试列表 37 | * @return 列表 38 | * @since 0.0.3 39 | */ 40 | private List buildCollectionList() { 41 | UserCollection user = new UserCollection(); 42 | String[] arrays = new String[]{"a", "b", "c"}; 43 | LinkedList lists = new LinkedList<>(Arrays.asList(arrays)); 44 | Map maps = new HashMap<>(); 45 | maps.put("key", "value"); 46 | maps.put("key2", "value2"); 47 | Set sets = new HashSet<>(); 48 | sets.add("set1"); 49 | sets.add("set2"); 50 | 51 | user.setLists(lists); 52 | user.setArrays(arrays); 53 | user.setMaps(maps); 54 | user.setSets(sets); 55 | return Arrays.asList(user); 56 | } 57 | ``` 58 | 59 | - 执行存储 60 | 61 | ```java 62 | public void collectionTest() { 63 | final String path = "src\\test\\resources\\collection.csv"; 64 | CsvWriteBs.newInstance(path) 65 | .write(buildCollectionList()); 66 | } 67 | ``` 68 | 69 | - 存储效果 70 | 71 | ``` 72 | arrays,lists,maps,sets 73 | a|b,a|b|c,key2=value2|key=value,set1|set2 74 | ``` 75 | 76 | ## 读取 77 | 78 | - 测试类 79 | 80 | ```java 81 | public void collectionTest() { 82 | final String path = "src\\test\\resources\\collection.csv"; 83 | List userList = CsvReadBs.newInstance(path) 84 | .read(UserCollection.class); 85 | System.out.println(userList); 86 | } 87 | ``` 88 | 89 | - 测试日志 90 | 91 | ``` 92 | [UserCollection{arrays=[a, b], lists=[a, b, c], maps={key=value, key2=value2}, sets=[set2, set1]}] 93 | ``` 94 | 95 | # 注意 96 | 97 | 为了保证 csv 以 `,` 分隔的统一性。 98 | 99 | 集合使用 `|` 进行分隔,其中 map 的 key/value 分隔,用到了 `=`。 100 | 101 | 在使用时要注意,不要包含上述的符号,否则会出现解析错乱。 -------------------------------------------------------------------------------- /doc/user/04-csv-支持内嵌对象.md: -------------------------------------------------------------------------------- 1 | # 支持内嵌对象 2 | 3 | 有时候我们希望像使用 mongo 一样,非常方便的存取 csv 的嵌套对象。 4 | 5 | 对于普通的 csv 都没有实现这个特性,本次做了一个尝试,支持内嵌对象的存取。 6 | 7 | ## 取舍 8 | 9 | 就像 csv 的简单,需要用到符号 `,` 一样。 10 | 11 | 内嵌对象为了不破坏 csv 的规范,使用了符号 `:`。 12 | 13 | 换言之,也就是对象内容中不能使用这个符号。 14 | 15 | 后期会针对出现的符号进行转义,避免这种冲突。 16 | 17 | # 测试案例 18 | 19 | 所有测试代码可以参考 [test]() 模块。 20 | 21 | ## 示例对象 22 | 23 | - UserEntry.java 24 | 25 | ```java 26 | public class UserEntry { 27 | 28 | /** 29 | * 名称 30 | */ 31 | private String name; 32 | 33 | /** 34 | * 内嵌的用户信息 35 | */ 36 | @CsvEntry 37 | private User user; 38 | 39 | //Getter/Setter/ToString 40 | } 41 | ``` 42 | 43 | 这里在需要内嵌的对象上使用注解 `@CsvEntry` 表示需要进行内嵌的对象转换。 44 | 45 | - User.java 46 | 47 | 其中 User 对象是原来使用的普通 java 对象 48 | 49 | ```java 50 | public class User { 51 | 52 | private String name; 53 | 54 | private int age; 55 | 56 | private float score; 57 | 58 | private double money; 59 | 60 | private boolean sex; 61 | 62 | private short level; 63 | 64 | private long id; 65 | 66 | private char status; 67 | 68 | private byte coin; 69 | 70 | //Getter/Setter/ToString 71 | } 72 | ``` 73 | 74 | ## 写入测试 75 | 76 | ```java 77 | public void entryTest() { 78 | final String path = "src\\test\\resources\\entry.csv"; 79 | CsvWriteBs.newInstance(path) 80 | .write(buildEntryList()); 81 | } 82 | ``` 83 | 84 | - buildEntryList() 85 | 86 | 负责对象构建代码,内容如下: 87 | 88 | ```java 89 | /** 90 | * 用户明细列表 91 | * @return 明细列表 92 | * @since 0.0.5 93 | */ 94 | private List buildEntryList() { 95 | UserEntry userEntry = new UserEntry(); 96 | userEntry.name("test"); 97 | userEntry.user(buildCommonList().get(0)); 98 | return Collections.singletonList(userEntry); 99 | } 100 | ``` 101 | 102 | - buildCommonList() 103 | 104 | ```java 105 | private List buildCommonList() { 106 | User user = new User(); 107 | short s = 4; 108 | byte b = 1; 109 | user.age(10) 110 | .name("你好") 111 | .id(1L) 112 | .score(60) 113 | .coin(b) 114 | .level(s) 115 | .money(200) 116 | .sex(true) 117 | .status('Y'); 118 | return Arrays.asList(user); 119 | } 120 | ``` 121 | 122 | 生成文件效果 123 | 124 | ``` 125 | name,user 126 | test,你好:10:60.0:200.0:true:4:1:Y:1 127 | ``` 128 | 129 | 如你所见,这里内嵌对象的属性使用了 `:` 进行分隔。 130 | 131 | ## 读取测试 132 | 133 | ```java 134 | public void entryTest() { 135 | final String path = "src\\test\\resources\\entry.csv"; 136 | List userList = CsvReadBs.newInstance(path) 137 | .read(UserEntry.class); 138 | System.out.println(userList); 139 | } 140 | ``` 141 | 142 | 输出信息 143 | 144 | ``` 145 | [UserEntry{name='test', user=User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}}] 146 | ``` -------------------------------------------------------------------------------- /doc/user/05-csv-特殊字符转义.md: -------------------------------------------------------------------------------- 1 | # 特殊字符转义 2 | 3 | 在实际使用中,有时候我们会用到 `,|:=`。 4 | 5 | 这几个被使用的特殊字符。 6 | 7 | 如果你希望这些特殊的字符被正确的存取,那么可以使用 `escape` 属性执行。 8 | 9 | ## 特殊字符的转换 10 | 11 | | 原始 | 转义后 | 12 | |:--|:--| 13 | | `,` | `&CSV_COMMA;` | 14 | | `|` | `&CSV_OR;` | 15 | | `:` | `&CSV_COLON;`| 16 | | `=` | `&CSV_EUQAL;` | 17 | 18 | 下面演示一下如何使用 19 | 20 | 暂时转义字符不支持自定义。 21 | 22 | # 测试代码 23 | 24 | ## 写入测试 25 | 26 | ```java 27 | public void escapeTest() { 28 | final String path = "src\\test\\resources\\escape.csv"; 29 | CsvWriteBs.newInstance(path) 30 | .escape(true) 31 | .write(buildUserEscapeList()); 32 | } 33 | ``` 34 | 35 | - 生成文件效果 36 | 37 | ``` 38 | name,map,nameList,user 39 | one&CSV_COMMA;one,key&CSV_EUQAL;key=value&CSV_EUQAL;value,one&CSV_OR;one|two&CSV_OR;two,entry&CSV_COLON;name:0:0.0:0.0:false:0:0: :0 40 | ``` 41 | 42 | ### 相关代码 43 | 44 | - UserEscape.java 45 | 46 | 其中用到的对象为: 47 | 48 | ```java 49 | public class UserEscape { 50 | 51 | /** 52 | * 使用 , 53 | */ 54 | private String name; 55 | 56 | /** 57 | * 使用 map = 58 | */ 59 | private Map map; 60 | 61 | /** 62 | * 使用 | 63 | */ 64 | private List nameList; 65 | 66 | /** 67 | * 使用 : 68 | */ 69 | @CsvEntry 70 | private User user; 71 | 72 | //Getter & Setter & ToString() 73 | } 74 | ``` 75 | 76 | - buildUserEscapeList() 77 | 78 | 构建时,特意使用了特殊的字符。 79 | 80 | ```java 81 | private List buildUserEscapeList() { 82 | UserEscape escape = new UserEscape(); 83 | Map map = new HashMap<>(); 84 | map.put("key=key", "value=value"); 85 | User user = new User(); 86 | user.name("entry:name"); 87 | 88 | escape.name("one,one"); 89 | escape.nameList(Arrays.asList("one|one", "two|two")); 90 | escape.map(map); 91 | escape.user(user); 92 | 93 | return Collections.singletonList(escape); 94 | } 95 | ``` 96 | 97 | ## 读取测试 98 | 99 | ```java 100 | public void escapeTest() { 101 | final String path = "src\\test\\resources\\escape.csv"; 102 | List userList = CsvReadBs.newInstance(path) 103 | .escape(true) 104 | .read(UserEscape.class); 105 | System.out.println(userList); 106 | } 107 | ``` 108 | 109 | - 日志信息 110 | 111 | ``` 112 | [UserEscape{name='one,one', nameList=[one|one, two|two], user=User{name='entry:name', age=0, score=0.0, money=0.0, sex=false, level=0, id=0, status= , coin=0}, map={key=key=value=value}}] 113 | ``` 114 | 115 | -------------------------------------------------------------------------------- /doc/发布流程.md: -------------------------------------------------------------------------------- 1 | # 文档说明 2 | 3 | 本文档用于说明当前项目如何进行发布。 4 | 5 | 6 | # 发布流程 7 | 8 | ## push to mvn center 9 | 10 | ``` 11 | mvn clean deploy -P release 12 | ``` 13 | 14 | ## commit to github 15 | 16 | ``` 17 | git push 18 | ``` 19 | 20 | ## merge to master 21 | 22 | ``` 23 | git checkout master 24 | git pull 25 | git checkout branch 26 | git rebase master (用rebase合并主干的修改,如果有冲突在此时解决) 27 | git checkout master 28 | git merge branch 29 | git push 30 | ``` 31 | 32 | ## create new branch & checkout 33 | 34 | ``` 35 | git branch release_XXX 36 | git checkout release_XXX 37 | ``` 38 | 39 | ## modify project version 40 | 41 | ``` 42 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=paradise* -DoldVersion=1.1.2 -DnewVersion=1.1.3-SNAPSHOT--> 43 | mvn -N versions:update-child-modules 44 | mvn versions:commit 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /doc/版本迭代规范.md: -------------------------------------------------------------------------------- 1 | # 版本类型 2 | 3 | x.y.z 4 | 5 | x 表示大版本之间的迭代,可能出现前后的不兼容。 6 | 7 | y 表示新特性,每次新加一个新特性,都会提升 y 的版本号。 8 | 9 | z 表示修复版本号,如果为第一版,则 z=1。后续会依次提升。 10 | 11 | ## 使用的版本选择 12 | 13 | 如果在较为正式的环境使用,建议使用 x.y 相同,z 数值最大的版本。 14 | 15 | 因为这个版本为尽可能修复已知的 bug。 16 | 17 | ## 新特性 18 | 19 | 不同版本的新特性,参见变更日志。 20 | 21 | # 版本的兼容性 22 | 23 | 在同一个 x 大版本中,禁止直接删除类信息。 24 | 25 | 所有的废弃使用 `@Depretectd` 注解、 26 | 27 | ## 必须有对应的测试 28 | 29 | 对应的测试信息。 30 | 31 | 保证代码的正确性。 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.houbb 8 | csv 9 | 0.2.0 10 | 11 | 12 | 13 | 3.2 14 | 3.2 15 | 2.18.1 16 | false 17 | false 18 | 19 | 2.2.1 20 | 2.9.1 21 | 1.5 22 | 23 | 24 | UTF-8 25 | 1.7 26 | 27 | 28 | 0.1.96 29 | 30 | 31 | 4.12 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | com.github.houbb 41 | heaven 42 | ${heaven.version} 43 | 44 | 45 | 46 | 47 | junit 48 | junit 49 | ${junit.version} 50 | true 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | com.github.houbb 63 | heaven 64 | 65 | 66 | 67 | 68 | junit 69 | junit 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-compiler-plugin 80 | ${plugin.compiler.version} 81 | 82 | ${project.compiler.level} 83 | ${project.compiler.level} 84 | ${project.build.sourceEncoding} 85 | 86 | 87 | 88 | 89 | org.apache.maven.plugins 90 | maven-surefire-plugin 91 | ${plugin.surefire.version} 92 | 93 | ${plugin.surefire.skip-it} 94 | ${plugin.surefire.ignore-failure} 95 | 96 | 97 | 98 | 99 | 100 | org.eluder.coveralls 101 | coveralls-maven-plugin 102 | 4.3.0 103 | 104 | 105 | 106 | org.codehaus.mojo 107 | cobertura-maven-plugin 108 | 2.7 109 | 110 | xml 111 | 256m 112 | 113 | true 114 | 115 | 116 | **/*Test.class 117 | **/HelpMojo.class 118 | **/*Vo.class 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | org.sonarsource.scanner.maven 128 | sonar-maven-plugin 129 | 3.1.1 130 | 131 | 132 | 133 | 134 | org.apache.maven.plugins 135 | maven-javadoc-plugin 136 | ${plugin.maven-javadoc-plugin.version} 137 | 138 | 139 | 140 | 141 | 142 | 143 | csv 144 | The csv read/write tool based on java annotation. 145 | 146 | 147 | org.sonatype.oss 148 | oss-parent 149 | 7 150 | 151 | 152 | 153 | The Apache Software License, Version 2.0 154 | http://www.apache.org/licenses/LICENSE-2.0.txt 155 | repo 156 | 157 | 158 | 159 | https://github.com/houbb/csv 160 | https://github.com/houbb/csv.git 161 | https://houbb.github.io/ 162 | 163 | 164 | 165 | houbb 166 | houbinbin.echo@gmail.com 167 | https://houbb.github.io/ 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | release 176 | 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-source-plugin 182 | ${plugin.maven-source-plugin.version} 183 | 184 | 185 | package 186 | 187 | jar-no-fork 188 | 189 | 190 | 191 | 192 | 193 | 194 | org.apache.maven.plugins 195 | maven-javadoc-plugin 196 | ${plugin.maven-javadoc-plugin.version} 197 | 198 | 199 | package 200 | 201 | jar 202 | 203 | 204 | 205 | 206 | 207 | 208 | org.apache.maven.plugins 209 | maven-gpg-plugin 210 | ${plugin.maven-gpg-plugin.version} 211 | 212 | 213 | verify 214 | 215 | sign 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | oss 225 | https://oss.sonatype.org/content/repositories/snapshots/ 226 | 227 | 228 | oss 229 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /release.bat: -------------------------------------------------------------------------------- 1 | :: 用于 release 当前项目(windows) 2 | :: author: houbb 3 | :: LastUpdateTime: 2018-1-22 09:08:52 4 | :: 用法:双击运行,或者当前路径 cmd 直接输入 release.bat 5 | 6 | :: 关闭回显 7 | @echo OFF 8 | 9 | ECHO "============================= RELEASE START..." 10 | 11 | :: 版本号信息(需要手动指定) 12 | :::: 旧版本名称 13 | SET version=0.2.0 14 | :::: 新版本名称 15 | SET newVersion=0.3.0 16 | :::: 组织名称 17 | SET groupName=com.github.houbb 18 | :::: 项目名称 19 | SET projectName=csv 20 | 21 | :: release 项目版本 22 | :::: snapshot 版本号 23 | SET snapshot_version=%version%"-SNAPSHOT" 24 | :::: 新的版本号 25 | SET release_version=%version% 26 | 27 | call mvn versions:set -DgroupId=%groupName% -DartifactId=%projectName% -DoldVersion=%snapshot_version% -DnewVersion=%release_version% 28 | call mvn -N versions:update-child-modules 29 | call mvn versions:commit 30 | call echo "1. RELEASE %snapshot_version% TO %release_version% DONE." 31 | 32 | 33 | :: 推送到 github 34 | git add . 35 | git commit -m "release branch %version%" 36 | git push 37 | git status 38 | 39 | ECHO "2. PUSH TO GITHUB DONE." 40 | 41 | :: 推送到 maven 中央仓库 42 | call mvn clean deploy -P release 43 | ECHO "3 PUSH TO MVN CENTER DONE." 44 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "============================= RELEASE START..." 3 | 4 | ## 版本号信息(需要手动指定) 5 | version="0.0.1" 6 | newVersion="0.0.2" 7 | projectName="csv" 8 | 9 | # release 项目版本 10 | ## snapshot 版本号 11 | snapshot_version=${version}"-SNAPSHOT" 12 | ## 新的版本号 13 | release_version=${version} 14 | 15 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=${projectName} -DoldVersion=${snapshot_version} -DnewVersion=${release_version} 16 | mvn -N versions:update-child-modules 17 | mvn versions:commit 18 | echo "1. RELEASE ${snapshot_version} TO ${release_version} DONE." 19 | 20 | 21 | # 推送到 github 22 | git add . 23 | git commit -m "release branch ${version}" 24 | git push 25 | git status 26 | 27 | echo "2. PUSH TO GITHUB DONE." 28 | 29 | 30 | # 推送到 maven 中央仓库 31 | mvn clean deploy -P release 32 | 33 | echo "3. PUSH TO MAVEN CENTER DONE." 34 | 35 | # 合并到 master 分支 36 | branchName="release_"${version} # 分支名称 37 | git checkout master 38 | git pull 39 | git checkout ${branchName} 40 | git rebase master 41 | git checkout master 42 | git merge ${branchName} 43 | git push 44 | 45 | echo "4. MERGE TO MASTER DONE." 46 | 47 | 48 | # 拉取新的分支 49 | newBranchName="release_"${newVersion} 50 | git branch ${newBranchName} 51 | git checkout ${newBranchName} 52 | git push --set-upstream origin ${newBranchName} 53 | 54 | echo "5. NEW BRANCH DONE." 55 | 56 | # 修改新分支的版本号 57 | ## snapshot 版本号 58 | snapshot_new_version=${newVersion}"-SNAPSHOT" 59 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=${projectName} -DoldVersion=${release_version} -DnewVersion=${snapshot_new_version} 60 | mvn -N versions:update-child-modules 61 | mvn versions:commit 62 | 63 | git add . 64 | git commit -m "modify branch ${release_version} TO ${snapshot_new_version}" 65 | git push 66 | git status 67 | echo "6. MODIFY ${release_version} TO ${snapshot_new_version} DONE." 68 | 69 | echo "============================= RELEASE END..." 70 | 71 | 72 | # 使用方式: 73 | # 1. 赋值权限: chmod +x ./release.sh 74 | # 2. 执行: ./release.sh 75 | # Last Update Time: 2018-01-20 13:17:06 76 | # Author: houbb 77 | 78 | 79 | -------------------------------------------------------------------------------- /release_rm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "============================= RELEASE START..." 3 | 4 | ## 版本号信息(需要手动指定) 5 | oldVersion="1.0.0" 6 | newVersion="1.0.0" 7 | projectName="csv" 8 | 9 | # 删除分支 10 | oldBranchName="release_"${oldVersion} 11 | git branch -d ${oldBranchName} 12 | git push origin --delete ${oldBranchName} 13 | 14 | echo "1. Branch remove success..." 15 | 16 | # 拉取新的分支 17 | newBranchName="release_"${newVersion} 18 | git branch ${newBranchName} 19 | git checkout ${newBranchName} 20 | git push --set-upstream origin ${newBranchName} 21 | 22 | echo "2. NEW BRANCH DONE." 23 | 24 | # 修改新分支的版本号 25 | ## snapshot 版本号 26 | snapshot_new_version=${newVersion}"-SNAPSHOT" 27 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=${projectName} -DoldVersion=${release_version} -DnewVersion=${snapshot_new_version} 28 | mvn -N versions:update-child-modules 29 | mvn versions:commit 30 | 31 | git add . 32 | git commit -m "modify branch ${release_version} TO ${snapshot_new_version}" 33 | git push 34 | git status 35 | echo "3. MODIFY ${release_version} TO ${snapshot_new_version} DONE." 36 | 37 | echo "============================= BRANCH RE-CREATE END..." 38 | 39 | echo "============================= BRANCH LIST =============================" 40 | git branch -a 41 | 42 | # 使用方式: 43 | # 注意:本脚本用于删除分支,谨慎使用! 44 | # 1. 赋值权限: chmod +x ./release_rm.sh 45 | # 2. 执行: ./release_rm.sh 46 | # Last Update Time: 2018-06-21 11:10:42 47 | # Author: houbb -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/annotation/Csv.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.annotation; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.api.IWriteConverter; 5 | import com.github.houbb.csv.support.convert.read.CommonReadConverter; 6 | import com.github.houbb.csv.support.convert.write.CommonWriteConverter; 7 | 8 | import java.lang.annotation.*; 9 | 10 | /** 11 | * CSV 注解 12 | * @author binbin.hou 13 | * @since 0.0.1 14 | */ 15 | @Documented 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Inherited 18 | @Target(ElementType.FIELD) 19 | public @interface Csv { 20 | 21 | /** 22 | * 字段显示名称 23 | * 1. 默认使用 field.name 24 | * @return 显示名称 25 | */ 26 | String label() default ""; 27 | 28 | /** 29 | * 读取是否需要 30 | * @return 是 31 | */ 32 | boolean readRequire() default true; 33 | 34 | /** 35 | * 写入是否需要 36 | * @return 是 37 | */ 38 | boolean writeRequire() default true; 39 | 40 | /** 41 | * 读取转换 42 | * @return 处理实现类 43 | */ 44 | Class readConverter() default CommonReadConverter.class; 45 | 46 | /** 47 | * 写入转换 48 | * @return 处理实现类 49 | */ 50 | Class writeConverter() default CommonWriteConverter.class; 51 | 52 | /** 53 | * 读映射 54 | * 55 | * S:成功;F:失败 56 | * 枚举值用 ; 分割,映射用 : 分割。 57 | * 58 | * 优先级:相比较 readConverter 优先使用 readMapping,如果值不为空,且当前字段的值为 String,才进行处理。否则忽略。 59 | * 注意:必须要有 : 分割符号,否则报错。只对 String 类型字段生效。 60 | * @return 读 61 | * @since 0.1.0 62 | */ 63 | String readMapping() default ""; 64 | 65 | /** 66 | * 写映射 67 | * 68 | * 优先级:相比较 writeConverter 优先使用 writeMapping,如果值不为空,且当前字段的值为 String,才进行处理。否则忽略。 69 | * 注意:必须要有 : 分割符号,否则报错。只对 String 类型字段生效。 70 | * @return 映射结果 71 | * @since 0.1.0 72 | */ 73 | String writeMapping() default ""; 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/annotation/CsvEntry.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * CSV 内嵌类注解 7 | * (1)放在对象字段,或者对象列表字段上。 8 | * (2)如果放在 map 上,或者放在非对象字段上。则直接忽略。 9 | * (3)单独使用时,会采用内嵌的模式。 10 | * (4)和 {@link Csv} 共同使用时,优先以注解指定的为准。 11 | * 默认的就是 {@link com.github.houbb.csv.support.convert.read.CommonReadConverter} 和 12 | * {@link com.github.houbb.csv.support.convert.write.CommonWriteConverter} 13 | * 14 | * @author binbin.hou 15 | * @since 0.0.4 16 | */ 17 | @Documented 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Inherited 20 | @Target({ElementType.FIELD}) 21 | public @interface CsvEntry { 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/api/ICodeDesc.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.api; 2 | 3 | /** 4 | * 枚举值编码和描述接口 5 | * @author binbin.hou 6 | * @since 0.1.0 7 | */ 8 | public interface ICodeDesc { 9 | 10 | /** 11 | * 获取编码 12 | * @return 编码 13 | * @since 0.1.0 14 | */ 15 | String getCode(); 16 | 17 | /** 18 | * 获取描述 19 | * @return 描述 20 | * @since 0.1.0 21 | */ 22 | String getDesc(); 23 | 24 | /** 25 | * 列表 26 | * @return 列表 27 | * @since 0.1.0 28 | */ 29 | ICodeDesc[] list(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/api/ICsv.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.api; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * CSV 读写接口 7 | * @author binbin.hou 8 | * @since 0.0.1 9 | * @param 泛型 10 | */ 11 | public interface ICsv { 12 | 13 | /** 14 | * 写入 15 | * @param context 上下文 16 | * @return 写入的字符串列表 17 | * @since 0.0.8 18 | */ 19 | List write(IWriteContext context); 20 | 21 | /** 22 | * 读取 23 | * @param context 上下文 24 | * @return 列表 25 | */ 26 | List read(IReadContext context); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/api/IReadContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.api; 2 | 3 | import com.github.houbb.csv.support.reader.ICsvReader; 4 | import com.github.houbb.heaven.support.sort.ISort; 5 | 6 | /** 7 | * 读取上下文 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | * @param 泛型 11 | */ 12 | public interface IReadContext { 13 | 14 | /** 15 | * 读取类 16 | * @return 实现 17 | * @since 0.0.8 18 | */ 19 | ICsvReader reader(); 20 | 21 | /** 22 | * 排序方式 23 | * @return 排序方式 24 | */ 25 | ISort sort(); 26 | 27 | /** 28 | * 读取的类型 29 | * @return 类型 30 | */ 31 | Class readClass(); 32 | 33 | /** 34 | * 开始的下标 35 | * 备注:参见 {@link java.io.RandomAccessFile} 随机读写文件 36 | * @return 开始的下标 37 | */ 38 | int startIndex(); 39 | 40 | /** 41 | * 结束的下标 42 | * @return 结束的下标 43 | */ 44 | int endIndex(); 45 | 46 | /** 47 | * 是否进行特殊字符转义 48 | * @since 0.0.6 49 | * @return 是否 50 | */ 51 | boolean escape(); 52 | 53 | /** 54 | * 引用字符 55 | * @return 字符 56 | * @since 0.2.0 57 | */ 58 | char quoteChar(); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/api/IReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.api; 2 | 3 | import com.github.houbb.csv.support.context.SingleReadContext; 4 | 5 | /** 6 | * 读取转换器,将 string 转换为 field 7 | * @author binbin.hou 8 | * @since 0.0.1 9 | * @param 泛型 10 | */ 11 | public interface IReadConverter { 12 | 13 | /** 14 | * 执行转换 15 | * @param context 上下文 16 | * @return 结果 17 | */ 18 | T convert(final SingleReadContext context); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/api/IWriteContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.api; 2 | 3 | import com.github.houbb.csv.support.writer.ICsvWriter; 4 | import com.github.houbb.heaven.support.sort.ISort; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 写入上下文 10 | * @author binbin.hou 11 | * @since 0.0.1 12 | * @param 泛型 13 | */ 14 | public interface IWriteContext { 15 | 16 | /** 17 | * 写入处理类 18 | * @return 实现 19 | * @since 0.0.8 20 | */ 21 | ICsvWriter writer(); 22 | 23 | /** 24 | * 是否写入标题头 25 | * @return 是否写入 head 行 26 | */ 27 | boolean writeHead(); 28 | 29 | /** 30 | * 是否写入 bom 头 31 | * @return 是否 32 | * @since 0.0.9 33 | */ 34 | boolean writeBom(); 35 | 36 | /** 37 | * 排序方式 38 | * @return 排序方式 39 | */ 40 | ISort sort(); 41 | 42 | /** 43 | * 待写入的列表 44 | * @return 待写入的列表 45 | */ 46 | List list(); 47 | 48 | /** 49 | * 是否进行特殊字符转移 50 | * @return 是否 51 | * @since 0.1.16 52 | */ 53 | boolean escape(); 54 | 55 | /** 56 | * 引用字符 57 | * @since 0.2.0 58 | * @return 引用字符 59 | */ 60 | char quoteChar(); 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/api/IWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.api; 2 | 3 | import com.github.houbb.csv.support.context.SingleWriteContext; 4 | 5 | /** 6 | * 读取转换器,将 field 转换为 string 7 | * @author binbin.hou 8 | * @since 0.0.1 9 | */ 10 | public interface IWriteConverter { 11 | 12 | /** 13 | * 执行转换 14 | * @param context 上下文 15 | * @return 字符串 16 | */ 17 | String convert(final SingleWriteContext context); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/bs/CsvReadBs.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.bs; 2 | 3 | import com.github.houbb.csv.api.ICsv; 4 | import com.github.houbb.csv.constant.CsvConfigConst; 5 | import com.github.houbb.csv.constant.CsvConst; 6 | import com.github.houbb.csv.support.context.DefaultReadContext; 7 | import com.github.houbb.csv.support.csv.DefaultCsv; 8 | import com.github.houbb.csv.support.csv.DefaultStringListCsv; 9 | import com.github.houbb.csv.support.reader.ICsvReader; 10 | import com.github.houbb.heaven.support.instance.impl.Instances; 11 | import com.github.houbb.heaven.support.sort.ISort; 12 | import com.github.houbb.heaven.support.sort.impl.NoSort; 13 | import com.github.houbb.heaven.util.common.ArgUtil; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * csv 读取引导类 19 | * @author binbin.hou 20 | * @since 0.0.1 21 | */ 22 | public final class CsvReadBs { 23 | 24 | /** 25 | * 读取类实现 26 | * @since 0.0.8 27 | */ 28 | private ICsvReader reader; 29 | 30 | /** 31 | * 开始下标 32 | * 1. 跳过第一行的 head 33 | */ 34 | private int startIndex = CsvConst.DEFAULT_START_INDEX; 35 | 36 | /** 37 | * 结束下标 38 | */ 39 | private int endIndex = CsvConst.DEFAULT_END_INDEX; 40 | 41 | /** 42 | * 执行转意 43 | * @since 0.0.6 44 | */ 45 | private boolean escape = false; 46 | 47 | /** 48 | * 引用字符 49 | * @since 0.2.0 50 | */ 51 | private char quoteChar = CsvConfigConst.DEFAULT_QUOTE_CHAR; 52 | 53 | /** 54 | * 无任何排序实现 55 | * @since 0.0.8 56 | */ 57 | @Deprecated 58 | private ISort sort = Instances.singleton(NoSort.class); 59 | 60 | /** 61 | * csv 默认实现 62 | * 63 | * @since 0.0.8 64 | */ 65 | private final ICsv csv = Instances.singleton(DefaultCsv.class); 66 | 67 | /** 68 | * 私有化构造器 69 | */ 70 | private CsvReadBs(){} 71 | 72 | /** 73 | * 新建对象 74 | * @return this 75 | * @since 0.0.1 76 | */ 77 | public static CsvReadBs newInstance() { 78 | return new CsvReadBs(); 79 | } 80 | 81 | /** 82 | * 读取类 83 | * @param reader 读取类 84 | * @return this 85 | * @since 0.0.8 86 | */ 87 | public CsvReadBs reader(ICsvReader reader) { 88 | ArgUtil.notNull(reader, "reader"); 89 | 90 | this.reader = reader; 91 | return this; 92 | } 93 | 94 | /** 95 | * 设置开始下标 96 | * @param startIndex 开始下标 97 | * @return this 98 | * @since 0.0.8 99 | */ 100 | public CsvReadBs startIndex(int startIndex) { 101 | this.startIndex = startIndex; 102 | return this; 103 | } 104 | 105 | /** 106 | * 设置结束下标 107 | * @param endIndex 结束下标 108 | * @return this 109 | * @since 0.0.8 110 | */ 111 | public CsvReadBs endIndex(int endIndex) { 112 | this.endIndex = endIndex; 113 | return this; 114 | } 115 | 116 | /** 117 | * 设置是否进行转义 118 | * @param escape 结束下标 119 | * @return this 120 | * @since 0.0.8 121 | */ 122 | public CsvReadBs escape(boolean escape) { 123 | this.escape = escape; 124 | return this; 125 | } 126 | 127 | public CsvReadBs quoteChar(char quoteChar) { 128 | this.quoteChar = quoteChar; 129 | return this; 130 | } 131 | 132 | /** 133 | * 将指定文件的内容读取到列表中 134 | * @param tClass 类型 135 | * @param 泛型 136 | * @return 列表 137 | */ 138 | @SuppressWarnings("unchecked") 139 | public List read(Class tClass) { 140 | DefaultReadContext context = new DefaultReadContext<>(); 141 | context.reader(reader) 142 | .startIndex(startIndex) 143 | .endIndex(endIndex) 144 | .sort(sort) 145 | .readClass(tClass) 146 | .escape(escape) 147 | .quoteChar(quoteChar) 148 | ; 149 | 150 | return csv.read(context); 151 | } 152 | 153 | /** 154 | * 将指定文件的内容读取到列表中 155 | * @return 列表 156 | * @since 0.2.0 157 | */ 158 | @SuppressWarnings("unchecked") 159 | public List> readStringList() { 160 | DefaultReadContext> context = new DefaultReadContext<>(); 161 | context.reader(reader) 162 | .startIndex(startIndex) 163 | .endIndex(endIndex) 164 | .sort(sort) 165 | .escape(escape) 166 | .quoteChar(quoteChar) 167 | ; 168 | 169 | ICsv> csv = new DefaultStringListCsv(); 170 | return csv.read(context); 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/bs/CsvWriteBs.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.bs; 2 | 3 | import com.github.houbb.csv.api.ICsv; 4 | import com.github.houbb.csv.constant.CsvConfigConst; 5 | import com.github.houbb.csv.support.context.DefaultWriteContext; 6 | import com.github.houbb.csv.support.csv.DefaultCsv; 7 | import com.github.houbb.csv.support.csv.DefaultStringListCsv; 8 | import com.github.houbb.csv.support.writer.ICsvWriter; 9 | import com.github.houbb.csv.support.writer.impl.CsvWriterNone; 10 | import com.github.houbb.heaven.support.instance.impl.Instances; 11 | import com.github.houbb.heaven.support.sort.ISort; 12 | import com.github.houbb.heaven.support.sort.impl.NoSort; 13 | import com.github.houbb.heaven.util.common.ArgUtil; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * csv 写入引导类 19 | * @author binbin.hou 20 | * @since 0.0.1 21 | */ 22 | public final class CsvWriteBs { 23 | 24 | /** 25 | * 是否写入 head 头信息 26 | * @since 0.0.1 27 | */ 28 | private boolean writeHead = true; 29 | 30 | /** 31 | * 是否写入 bom 头 32 | * @since 0.0.9 33 | */ 34 | private boolean writeBom = true; 35 | 36 | /** 37 | * csv 写入类操作 38 | * 39 | * 1. 默认什么都不做 40 | * @since 0.0.8 41 | */ 42 | private ICsvWriter writer = Instances.singleton(CsvWriterNone.class); 43 | 44 | /** 45 | * 指定排序方式 46 | * 47 | * @since 0.0.8 废弃 48 | */ 49 | @Deprecated 50 | private ISort sort = Instances.singleton(NoSort.class); 51 | 52 | /** 53 | * 特殊字符转换 54 | * @see com.github.houbb.csv.constant.CsvEscapeConst 特殊信息 55 | */ 56 | private boolean escape = false; 57 | 58 | /** 59 | * 默认 csv 实现 60 | * @since 0.0.8 61 | */ 62 | private ICsv csv = Instances.singleton(DefaultCsv.class); 63 | 64 | /** 65 | * 引用字符 66 | * @since 0.2.0 67 | */ 68 | private char quoteChar = CsvConfigConst.DEFAULT_QUOTE_CHAR; 69 | 70 | /** 71 | * 私有化构造器 72 | */ 73 | private CsvWriteBs(){} 74 | 75 | /** 76 | * 新建对象实例 77 | * @return 实现 78 | * @since 0.0.8 79 | */ 80 | public static CsvWriteBs newInstance() { 81 | return new CsvWriteBs(); 82 | } 83 | 84 | /** 85 | * 是否写入表头 86 | * @param writeHead 是否写入表头 87 | * @return 实现 88 | * @since 0.0.8 89 | */ 90 | public CsvWriteBs writeHead(boolean writeHead) { 91 | this.writeHead = writeHead; 92 | return this; 93 | } 94 | 95 | /** 96 | * 设置是否写入 bom 97 | * @param writeBom 写入 bom 98 | * @return this 99 | * @since 0.0.9 100 | */ 101 | public CsvWriteBs writeBom(boolean writeBom) { 102 | this.writeBom = writeBom; 103 | return this; 104 | } 105 | 106 | /** 107 | * 排序实现 108 | * @param sort 排序实现 109 | * @return this 110 | * @since 0.0.8 111 | */ 112 | public CsvWriteBs sort(ISort sort) { 113 | ArgUtil.notNull(sort, "sort"); 114 | 115 | this.sort = sort; 116 | return this; 117 | } 118 | 119 | /** 120 | * 是否进行转义 121 | * @param escape 是否 122 | * @return 实现 123 | * @since 0.0.8 124 | */ 125 | public CsvWriteBs escape(boolean escape) { 126 | this.escape = escape; 127 | return this; 128 | } 129 | 130 | /** 131 | * 设置写入实现类 132 | * @param writer 写入类 133 | * @return this 134 | * @since 0.0.8 135 | */ 136 | public CsvWriteBs writer(ICsvWriter writer) { 137 | ArgUtil.notNull(writer, "writer"); 138 | 139 | this.writer = writer; 140 | return this; 141 | } 142 | 143 | public CsvWriteBs quoteChar(char quoteChar) { 144 | this.quoteChar = quoteChar; 145 | return this; 146 | } 147 | 148 | /** 149 | * 将指定列表的内容写入到文件中 150 | * @param list 列表 151 | * @param 泛型 152 | * @return 写入的字符串列表 153 | */ 154 | @SuppressWarnings("unchecked") 155 | public List write(List list) { 156 | DefaultWriteContext context = new DefaultWriteContext<>(); 157 | context.list(list) 158 | .writeHead(writeHead) 159 | .writeBom(writeBom) 160 | .sort(sort) 161 | .escape(escape) 162 | .writer(writer) 163 | .quoteChar(quoteChar) 164 | ; 165 | 166 | return csv.write(context); 167 | } 168 | 169 | /** 170 | * @since 0.2.0 171 | * @param list 列表 172 | */ 173 | public void writeStringList(List> list) { 174 | DefaultWriteContext> context = new DefaultWriteContext<>(); 175 | context.list(list) 176 | .writeHead(writeHead) 177 | .writeBom(writeBom) 178 | .sort(sort) 179 | .escape(escape) 180 | .writer(writer) 181 | .quoteChar(quoteChar) 182 | ; 183 | 184 | ICsv> csv = new DefaultStringListCsv(); 185 | csv.write(context); 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/constant/CsvConfigConst.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.constant; 2 | 3 | /** 4 | * CSV 配置常量定义 5 | * @author binbin.hou 6 | * @since 0.2.0 7 | */ 8 | public final class CsvConfigConst { 9 | 10 | private CsvConfigConst(){} 11 | 12 | public static final char DEFAULT_QUOTE_CHAR = '"'; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/constant/CsvConst.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.constant; 2 | 3 | /** 4 | * CSV 常量定义 5 | * @author binbin.hou 6 | * @since 0.0.4 7 | */ 8 | public final class CsvConst { 9 | 10 | private CsvConst(){} 11 | 12 | /** 13 | * 逗号 14 | * 用于 CSV 标准的分隔字段信息。 15 | */ 16 | public static final String COMMA = ","; 17 | 18 | /** 19 | * 数组分隔符 or 20 | */ 21 | public static final String OR = "|"; 22 | 23 | /** 24 | * map 的 key=value 会使用 25 | */ 26 | public static final String EQUALS = "="; 27 | 28 | /** 29 | * 拆分数组(or) 30 | */ 31 | public static final String SPLIT_OR = "\\|"; 32 | 33 | /** 34 | * 明细分割单元-char 35 | * @since 0.0.5 36 | */ 37 | public static final char ENTRY_SPLIT_UNIT_CHAR = ':'; 38 | 39 | /** 40 | * 明细分割单元-char 41 | * @since 0.0.5 42 | */ 43 | public static final String ENTRY_SPLIT_UNIT = ":"; 44 | 45 | /** 46 | * 默认开始下标 47 | * @since 0.0.8 48 | */ 49 | public static final int DEFAULT_START_INDEX = 1; 50 | 51 | /** 52 | * 默认结束下标 53 | * @since 0.0.8 54 | */ 55 | public static final int DEFAULT_END_INDEX = Integer.MAX_VALUE; 56 | 57 | /** 58 | * 映射分割符号 59 | * @since 0.1.0 60 | */ 61 | public static final String MAPPING_SPLITTER = ";"; 62 | 63 | /** 64 | * 每一组元素的分割符号 65 | * @since 0.1.0 66 | */ 67 | public static final String MAPPING_UNIT_SPLITTER = ":"; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/constant/CsvEscapeConst.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.constant; 2 | 3 | /** 4 | * CSV 特殊符号转换常量 5 | * 6 | * 采用类似于 html 的特殊字符转移。 7 | * 用途: 8 | * (1)存储的时候,对字段属性进行统一替换 9 | * (2)读取的时候,对字段属性进行还原。 10 | * 11 | * 实现方式: 12 | * (1)代码写死,简单实现。(本期使用这种方式实现) 13 | * (2)更加灵活的方式,添加一层 readFilter writeFilter 14 | * 后期可以便于用户自行定义。 15 | * @author binbin.hou 16 | * @since 0.0.6 17 | */ 18 | public final class CsvEscapeConst { 19 | 20 | private CsvEscapeConst(){} 21 | 22 | /** 23 | * 逗号 24 | */ 25 | public static final String COMMA = "&CSV_COMMA;"; 26 | 27 | /** 28 | * OR 29 | */ 30 | public static final String OR = "&CSV_OR;"; 31 | 32 | /** 33 | * 等于 34 | */ 35 | public static final String EQUAL = "&CSV_EUQAL;"; 36 | 37 | /** 38 | * 冒号 39 | */ 40 | public static final String COLON = "&CSV_COLON;"; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/constant/CsvOperateType.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.constant; 2 | 3 | /** 4 | * csv 操作类型 5 | * @author binbin.hou 6 | * @since 0.0.1 7 | */ 8 | public enum CsvOperateType { 9 | 10 | /** 11 | * 读取 12 | */ 13 | READ, 14 | 15 | /** 16 | * 写入 17 | */ 18 | WRITE, 19 | ; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/constant/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.constant; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/exception/CsvException.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.exception; 2 | 3 | /** 4 | * @author binbin.hou 5 | * @since 0.0.8 6 | */ 7 | public class CsvException extends RuntimeException { 8 | 9 | public CsvException() { 10 | } 11 | 12 | public CsvException(String message) { 13 | super(message); 14 | } 15 | 16 | public CsvException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public CsvException(Throwable cause) { 21 | super(cause); 22 | } 23 | 24 | public CsvException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 25 | super(message, cause, enableSuppression, writableStackTrace); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/context/DefaultReadContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.context; 2 | 3 | import com.github.houbb.csv.api.IReadContext; 4 | import com.github.houbb.csv.support.reader.ICsvReader; 5 | import com.github.houbb.heaven.support.sort.ISort; 6 | 7 | /** 8 | * 默认读取上下文 9 | * @author binbin.hou 10 | * @since 0.0.1 11 | * @param 泛型 12 | */ 13 | public class DefaultReadContext implements IReadContext { 14 | 15 | /** 16 | * 读取类 17 | * @since 0.0.8 18 | */ 19 | private ICsvReader reader; 20 | 21 | private ISort sort; 22 | 23 | private Class readClass; 24 | 25 | private int startIndex; 26 | 27 | private int endIndex; 28 | 29 | private boolean escape; 30 | 31 | private char quoteChar; 32 | 33 | public DefaultReadContext newInstance() { 34 | return new DefaultReadContext<>(); 35 | } 36 | 37 | @Override 38 | public ICsvReader reader() { 39 | return reader; 40 | } 41 | 42 | public DefaultReadContext reader(ICsvReader reader) { 43 | this.reader = reader; 44 | return this; 45 | } 46 | 47 | @Override 48 | public ISort sort() { 49 | return sort; 50 | } 51 | 52 | public DefaultReadContext sort(ISort sort) { 53 | this.sort = sort; 54 | return this; 55 | } 56 | 57 | @Override 58 | public Class readClass() { 59 | return readClass; 60 | } 61 | 62 | public DefaultReadContext readClass(Class readClass) { 63 | this.readClass = readClass; 64 | return this; 65 | } 66 | 67 | @Override 68 | public int startIndex() { 69 | return startIndex; 70 | } 71 | 72 | public DefaultReadContext startIndex(int startIndex) { 73 | this.startIndex = startIndex; 74 | return this; 75 | } 76 | 77 | @Override 78 | public int endIndex() { 79 | return endIndex; 80 | } 81 | 82 | public DefaultReadContext endIndex(int endIndex) { 83 | this.endIndex = endIndex; 84 | return this; 85 | } 86 | 87 | @Override 88 | public boolean escape() { 89 | return escape; 90 | } 91 | 92 | 93 | public DefaultReadContext escape(boolean escape) { 94 | this.escape = escape; 95 | return this; 96 | } 97 | 98 | public char quoteChar() { 99 | return quoteChar; 100 | } 101 | 102 | public DefaultReadContext quoteChar(char quoteChar) { 103 | this.quoteChar = quoteChar; 104 | return this; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/context/DefaultWriteContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.context; 2 | 3 | import com.github.houbb.csv.api.IWriteContext; 4 | import com.github.houbb.csv.support.writer.ICsvWriter; 5 | import com.github.houbb.heaven.support.sort.ISort; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 默认写入上下文 11 | * @author binbin.hou 12 | * @since 0.0.1 13 | * @param 泛型 14 | */ 15 | public class DefaultWriteContext implements IWriteContext { 16 | 17 | /** 18 | * 写入处理类 19 | * @since 0.0.8 20 | */ 21 | private ICsvWriter writer; 22 | 23 | /** 24 | * 是否写入表头 25 | * @since 0.0.8 26 | */ 27 | private boolean writeHead; 28 | 29 | /** 30 | * 是否写入 bom 头 31 | * @since 0.0.9 32 | */ 33 | private boolean writeBom; 34 | 35 | /** 36 | * 排序算法 37 | * @since 0.0.8 38 | */ 39 | private ISort sort; 40 | 41 | /** 42 | * 待写入列表 43 | * @since 0.0.8 44 | */ 45 | private List list; 46 | 47 | /** 48 | * 是否启动转换 49 | * @since 0.0.6 50 | */ 51 | private boolean escape; 52 | 53 | /** 54 | * @since 0.2.0 55 | */ 56 | private char quoteChar; 57 | 58 | @Override 59 | public ICsvWriter writer() { 60 | return writer; 61 | } 62 | 63 | public DefaultWriteContext writer(ICsvWriter writer) { 64 | this.writer = writer; 65 | return this; 66 | } 67 | 68 | @Override 69 | public boolean writeHead() { 70 | return writeHead; 71 | } 72 | 73 | public DefaultWriteContext writeHead(boolean writeHead) { 74 | this.writeHead = writeHead; 75 | return this; 76 | } 77 | 78 | @Override 79 | public boolean writeBom() { 80 | return writeBom; 81 | } 82 | 83 | public DefaultWriteContext writeBom(boolean writeBom) { 84 | this.writeBom = writeBom; 85 | return this; 86 | } 87 | 88 | @Override 89 | public ISort sort() { 90 | return sort; 91 | } 92 | 93 | public DefaultWriteContext sort(ISort sort) { 94 | this.sort = sort; 95 | return this; 96 | } 97 | 98 | @Override 99 | public List list() { 100 | return list; 101 | } 102 | 103 | public DefaultWriteContext list(List list) { 104 | this.list = list; 105 | return this; 106 | } 107 | 108 | @Override 109 | public boolean escape() { 110 | return escape; 111 | } 112 | 113 | public DefaultWriteContext escape(boolean escape) { 114 | this.escape = escape; 115 | return this; 116 | } 117 | 118 | @Override 119 | public char quoteChar() { 120 | return quoteChar; 121 | } 122 | 123 | public DefaultWriteContext quoteChar(char quoteChar) { 124 | this.quoteChar = quoteChar; 125 | return this; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/context/SingleReadContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.context; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.heaven.support.sort.ISort; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | * 单个元素读取上下文 10 | * @author binbin.hou 11 | * @since 0.0.4 12 | */ 13 | public class SingleReadContext { 14 | 15 | /** 16 | * 字符串的值 17 | */ 18 | private String value; 19 | 20 | /** 21 | * 当前字段信息 22 | */ 23 | private Field field; 24 | 25 | /** 26 | * 字段类型 27 | */ 28 | private Class fieldType; 29 | 30 | /** 31 | * 类信息 32 | */ 33 | private Class classType; 34 | 35 | /** 36 | * 排序信息 37 | */ 38 | private ISort sort; 39 | 40 | /** 41 | * 分隔符号 42 | * 默认使用:, 43 | * 一级明细:: 44 | * 二级明细::: 45 | * 三级明细: ::: 46 | * 依次类推。 47 | * 48 | * 目的:为了保证 , 号的语意性。 49 | * @since 0.0.5 50 | */ 51 | private String split; 52 | 53 | /** 54 | * 特殊字符的转义 55 | * @since 0.0.6 56 | */ 57 | private boolean escape; 58 | 59 | /** 60 | * csv 注解信息 61 | * @since 0.1.0 62 | */ 63 | private Csv csv; 64 | 65 | /** 66 | * 创建新的实例 67 | * @return 新的实例 68 | * @since 0.0.6 69 | */ 70 | public static SingleReadContext newInstance() { 71 | return new SingleReadContext(); 72 | } 73 | 74 | public String value() { 75 | return value; 76 | } 77 | 78 | public SingleReadContext value(String value) { 79 | this.value = value; 80 | return this; 81 | } 82 | 83 | public Field field() { 84 | return field; 85 | } 86 | 87 | public SingleReadContext field(Field field) { 88 | this.field = field; 89 | return this; 90 | } 91 | 92 | public Class fieldType() { 93 | return fieldType; 94 | } 95 | 96 | public SingleReadContext fieldType(Class fieldType) { 97 | this.fieldType = fieldType; 98 | return this; 99 | } 100 | 101 | public Class classType() { 102 | return classType; 103 | } 104 | 105 | public SingleReadContext classType(Class classType) { 106 | this.classType = classType; 107 | return this; 108 | } 109 | 110 | public ISort sort() { 111 | return sort; 112 | } 113 | 114 | public SingleReadContext sort(ISort sort) { 115 | this.sort = sort; 116 | return this; 117 | } 118 | 119 | public String split() { 120 | return split; 121 | } 122 | 123 | public SingleReadContext split(String split) { 124 | this.split = split; 125 | return this; 126 | } 127 | 128 | public boolean escape() { 129 | return escape; 130 | } 131 | 132 | public SingleReadContext escape(boolean escape) { 133 | this.escape = escape; 134 | return this; 135 | } 136 | 137 | public Csv csv() { 138 | return csv; 139 | } 140 | 141 | public SingleReadContext csv(Csv csv) { 142 | this.csv = csv; 143 | return this; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/context/SingleWriteContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.context; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.heaven.support.sort.ISort; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | * 单个元素上下文 10 | * 11 | * 后期可能会添加:cache 12 | * @author binbin.hou 13 | * @since 0.0.4 14 | */ 15 | public class SingleWriteContext { 16 | 17 | /** 18 | * 创建一个全新的实例 19 | * @return 实例 20 | * @since 0.0.6 21 | */ 22 | public static SingleWriteContext newInstance() { 23 | return new SingleWriteContext(); 24 | } 25 | 26 | /** 27 | * 排序 28 | */ 29 | private ISort sort; 30 | 31 | /** 32 | * 单个元素 33 | */ 34 | private Object element; 35 | 36 | /** 37 | * 当前字段信息 38 | * @since 0.0.5 39 | */ 40 | private Field field; 41 | 42 | /** 43 | * 当前字段的值 44 | * @since 0.0.5 45 | */ 46 | private Object value; 47 | 48 | /** 49 | * 分隔符号 50 | * 默认使用:, 51 | * 一级明细:: 52 | * 二级明细::: 53 | * 三级明细: ::: 54 | * 依次类推。 55 | * 56 | * 目的:为了保证 , 号的语意性。 57 | * @since 0.0.5 58 | */ 59 | private String split; 60 | 61 | /** 62 | * 特殊字符转义 63 | * @since 0.0.6 64 | */ 65 | private boolean escape; 66 | 67 | /** 68 | * 注解信息 69 | * @since 0.1.0 70 | */ 71 | private Csv csv; 72 | 73 | public ISort sort() { 74 | return sort; 75 | } 76 | 77 | public SingleWriteContext sort(ISort sort) { 78 | this.sort = sort; 79 | return this; 80 | } 81 | 82 | public Object element() { 83 | return element; 84 | } 85 | 86 | public SingleWriteContext element(Object element) { 87 | this.element = element; 88 | return this; 89 | } 90 | 91 | public Field field() { 92 | return field; 93 | } 94 | 95 | public SingleWriteContext field(Field field) { 96 | this.field = field; 97 | return this; 98 | } 99 | 100 | public Object value() { 101 | return value; 102 | } 103 | 104 | public SingleWriteContext value(Object value) { 105 | this.value = value; 106 | return this; 107 | } 108 | 109 | public String split() { 110 | return split; 111 | } 112 | 113 | public SingleWriteContext split(String split) { 114 | this.split = split; 115 | return this; 116 | } 117 | 118 | public boolean escape() { 119 | return escape; 120 | } 121 | 122 | public SingleWriteContext escape(boolean escape) { 123 | this.escape = escape; 124 | return this; 125 | } 126 | 127 | public Csv csv() { 128 | return csv; 129 | } 130 | 131 | public SingleWriteContext csv(Csv csv) { 132 | this.csv = csv; 133 | return this; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/context/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.context; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/mapping/ReadMappingConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.mapping; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.support.context.SingleReadContext; 5 | import com.github.houbb.csv.util.CsvInnerUtil; 6 | import com.github.houbb.heaven.annotation.ThreadSafe; 7 | import com.github.houbb.heaven.util.lang.StringUtil; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * 读取转换器,将 string 转换为 field 13 | * @author binbin.hou 14 | * @since 0.1.0 15 | */ 16 | @ThreadSafe 17 | public class ReadMappingConverter implements IReadConverter { 18 | 19 | @Override 20 | public String convert(SingleReadContext context) { 21 | String value = context.value(); 22 | if(StringUtil.isEmpty(value)) { 23 | return value; 24 | } 25 | 26 | Map map = CsvInnerUtil.getMappingMap(context.csv().readMapping()); 27 | for(Map.Entry entry : map.entrySet()) { 28 | if(entry.getValue().equalsIgnoreCase(value)) { 29 | return entry.getKey(); 30 | } 31 | } 32 | return value; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/mapping/WriteMappingConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.mapping; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.support.context.SingleWriteContext; 5 | import com.github.houbb.csv.util.CsvInnerUtil; 6 | import com.github.houbb.heaven.annotation.ThreadSafe; 7 | import com.github.houbb.heaven.util.lang.ObjectUtil; 8 | import com.github.houbb.heaven.util.lang.StringUtil; 9 | import com.github.houbb.heaven.util.util.MapUtil; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * 写入转换器,将 string 转换为 field 15 | * @author binbin.hou 16 | * @since 0.1.0 17 | */ 18 | @ThreadSafe 19 | public class WriteMappingConverter implements IWriteConverter { 20 | 21 | @Override 22 | public String convert(SingleWriteContext context) { 23 | Object value = context.value(); 24 | if(ObjectUtil.isNull(value)) { 25 | return null; 26 | } 27 | 28 | String text = (String) context.value(); 29 | if(StringUtil.isEmpty(text)) { 30 | return text; 31 | } 32 | 33 | Map map = CsvInnerUtil.getMappingMap(context.csv().writeMapping()); 34 | return MapUtil.getMapValue(map, text, text); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/AbstractCodeDescReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read; 2 | 3 | import com.github.houbb.csv.api.ICodeDesc; 4 | import com.github.houbb.csv.api.IReadConverter; 5 | import com.github.houbb.csv.support.context.SingleReadContext; 6 | 7 | /** 8 | * 获取 label 描述映射为 code 转换类 9 | * @author binbin.hou 10 | * @see ICodeDesc 接口 11 | * @since 0.1.0 12 | */ 13 | public abstract class AbstractCodeDescReadConverter implements IReadConverter { 14 | 15 | /** 16 | * 获取映射类 17 | * @return 映射类 18 | * @since 0.1.0 19 | */ 20 | protected abstract E[] codeDescArray(); 21 | 22 | @Override 23 | public String convert(SingleReadContext context) { 24 | String label = context.value(); 25 | 26 | ICodeDesc[] codeDescArray = codeDescArray(); 27 | for(ICodeDesc entry : codeDescArray) { 28 | if(entry.getDesc().equalsIgnoreCase(label)) { 29 | return entry.getCode(); 30 | } 31 | } 32 | 33 | return label; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/AbstractCodeDescWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read; 2 | 3 | import com.github.houbb.csv.api.ICodeDesc; 4 | import com.github.houbb.csv.api.IReadConverter; 5 | import com.github.houbb.csv.support.context.SingleReadContext; 6 | 7 | /** 8 | * 获取编码描述映射转换类 9 | * @author binbin.hou 10 | * @see ICodeDesc 接口 11 | * @since 0.1.0 12 | */ 13 | public abstract class AbstractCodeDescWriteConverter implements IReadConverter { 14 | 15 | /** 16 | * 获取映射类 17 | * @return 映射类 18 | * @since 0.1.0 19 | */ 20 | protected abstract E[] codeDescArray(); 21 | 22 | @Override 23 | public String convert(SingleReadContext context) { 24 | String code = context.value(); 25 | 26 | ICodeDesc[] codeDescArray = codeDescArray(); 27 | for(ICodeDesc entry : codeDescArray) { 28 | if(entry.getCode().equalsIgnoreCase(code)) { 29 | return entry.getDesc(); 30 | } 31 | } 32 | 33 | return code; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/CommonReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.support.context.SingleReadContext; 5 | import com.github.houbb.csv.support.convert.read.collection.ArrayReadConverter; 6 | import com.github.houbb.csv.support.convert.read.collection.CollectionReadConverter; 7 | import com.github.houbb.csv.support.convert.read.collection.MapReadConverter; 8 | import com.github.houbb.csv.support.convert.read.entry.EntryReadConverter; 9 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 10 | import com.github.houbb.csv.support.convert.read.type.impl.*; 11 | import com.github.houbb.csv.util.CsvFieldUtil; 12 | import com.github.houbb.csv.util.CsvInnerUtil; 13 | import com.github.houbb.heaven.annotation.ThreadSafe; 14 | import com.github.houbb.heaven.support.instance.impl.InstanceFactory; 15 | import com.github.houbb.heaven.support.instance.impl.Instances; 16 | import com.github.houbb.heaven.support.sort.ISort; 17 | import com.github.houbb.heaven.util.lang.ObjectUtil; 18 | import com.github.houbb.heaven.util.lang.StringUtil; 19 | import com.github.houbb.heaven.util.lang.reflect.ClassTypeUtil; 20 | import com.github.houbb.heaven.util.lang.reflect.PrimitiveUtil; 21 | 22 | import java.lang.reflect.Field; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | /** 27 | * 通用读取转换器 28 | * @author binbin.hou 29 | * @since 0.0.1 30 | */ 31 | @ThreadSafe 32 | public class CommonReadConverter implements IReadConverter { 33 | 34 | /** 35 | * 转换器映射关系 36 | */ 37 | private static final Map CONVERTER_MAP = new HashMap<>(); 38 | 39 | static { 40 | CONVERTER_MAP.put(String.class, InstanceFactory.getInstance().singleton(StringReadConverter.class)); 41 | CONVERTER_MAP.put(Byte.class, InstanceFactory.getInstance().singleton(ByteReadConverter.class)); 42 | CONVERTER_MAP.put(Boolean.class, InstanceFactory.getInstance().singleton(BooleanReadConverter.class)); 43 | CONVERTER_MAP.put(Short.class, InstanceFactory.getInstance().singleton(ShortReadConverter.class)); 44 | CONVERTER_MAP.put(Integer.class, InstanceFactory.getInstance().singleton(IntegerReadConverter.class)); 45 | CONVERTER_MAP.put(Long.class, InstanceFactory.getInstance().singleton(LongReadConverter.class)); 46 | CONVERTER_MAP.put(Float.class, InstanceFactory.getInstance().singleton(FloatReadConverter.class)); 47 | CONVERTER_MAP.put(Double.class, InstanceFactory.getInstance().singleton(DoubleReadConverter.class)); 48 | CONVERTER_MAP.put(Character.class, InstanceFactory.getInstance().singleton(CharacterReadConverter.class)); 49 | } 50 | 51 | @Override 52 | public Object convert(final SingleReadContext context) { 53 | final String value = context.value(); 54 | final Field field = context.field(); 55 | final String split = context.split(); 56 | final ISort sort = context.sort(); 57 | 58 | //1. 为空判断 59 | if(StringUtil.isEmpty(value)) { 60 | return null; 61 | } 62 | 63 | // 获取当前字段类型 64 | Class refType = field.getType(); 65 | 66 | //2 特殊集合的处理 67 | // 2.1 数组 68 | if(ClassTypeUtil.isArray(refType)) { 69 | return Instances.singleton(ArrayReadConverter.class).convert(context); 70 | } 71 | // 2.2 map 72 | if(ClassTypeUtil.isMap(refType)) { 73 | return Instances.singleton(MapReadConverter.class).convert(context); 74 | } 75 | // 2.3 collection 76 | if(ClassTypeUtil.isCollection(refType)) { 77 | return Instances.singleton(CollectionReadConverter.class).convert(context); 78 | } 79 | // 2.4 对象 80 | // 当前字段指定为 @CsvEntry 且为对象 81 | if(CsvFieldUtil.isEntryAble(field)) { 82 | final String nextSplit = CsvInnerUtil.getNextSplit(split); 83 | SingleReadContext singleReadContext = new SingleReadContext(); 84 | singleReadContext.sort(sort) 85 | .value(value) 86 | .split(nextSplit) 87 | .classType(refType) 88 | .field(field) 89 | .escape(context.escape()) 90 | ; 91 | return Instances.singleton(EntryReadConverter.class).convert(singleReadContext); 92 | } 93 | 94 | // 3. 基本类型 95 | final boolean escape = context.escape(); 96 | return this.convert(value, refType, escape); 97 | } 98 | 99 | /** 100 | * 根据类型进行转换 101 | * @param value 字符串的值 102 | * @param type 字段的类型 103 | * @param escape 是否进行特殊字符转义 since 0.0.6 104 | * @return 转换的结果 105 | */ 106 | public Object convert(String value, final Class type, 107 | final boolean escape) { 108 | //1. 快速返回 109 | if(StringUtil.isEmpty(value) 110 | || ObjectUtil.isNull(type)) { 111 | return null; 112 | } 113 | 114 | // 2. 根据类型处理 115 | Class actualType = type; 116 | if(actualType.isPrimitive()) { 117 | actualType = PrimitiveUtil.getReferenceType(actualType); 118 | } 119 | ITypeConverter readConverter = CONVERTER_MAP.get(actualType); 120 | if(ObjectUtil.isNotNull(readConverter)) { 121 | if(escape) { 122 | value = CsvInnerUtil.replaceAllEscape(value); 123 | } 124 | return readConverter.convert(value, actualType); 125 | } 126 | 127 | //3. 不属于基本类型,则直接返回 null 128 | return null; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/collection/ArrayReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.collection; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.constant.CsvConst; 5 | import com.github.houbb.csv.support.context.SingleReadContext; 6 | import com.github.houbb.csv.support.convert.read.CommonReadConverter; 7 | import com.github.houbb.heaven.annotation.ThreadSafe; 8 | import com.github.houbb.heaven.support.instance.impl.Instances; 9 | import com.github.houbb.heaven.util.lang.reflect.ReflectFieldUtil; 10 | 11 | import java.lang.reflect.Array; 12 | import java.lang.reflect.Field; 13 | 14 | /** 15 | * 数组读取 16 | * 17 | * @author binbin.hou 18 | * @since 0.0.3 19 | */ 20 | @ThreadSafe 21 | public class ArrayReadConverter implements IReadConverter { 22 | 23 | @Override 24 | public Object convert(SingleReadContext context) { 25 | final String value = context.value(); 26 | final Field field = context.field(); 27 | 28 | String[] strings = value.split(CsvConst.SPLIT_OR); 29 | Class componentType = ReflectFieldUtil.getComponentType(field); 30 | Object[] arrays = (Object[]) Array.newInstance(componentType, strings.length); 31 | 32 | final CommonReadConverter readConverter = Instances.singleton(CommonReadConverter.class); 33 | for (int i = 0; i < strings.length; i++) { 34 | final Object entryValue = readConverter.convert(strings[i], componentType, context.escape()); 35 | Array.set(arrays, i, entryValue); 36 | } 37 | return arrays; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/collection/CollectionReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.collection; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.constant.CsvConst; 5 | import com.github.houbb.csv.support.context.SingleReadContext; 6 | import com.github.houbb.csv.support.convert.read.CommonReadConverter; 7 | import com.github.houbb.heaven.support.instance.impl.Instances; 8 | import com.github.houbb.heaven.util.guava.Guavas; 9 | import com.github.houbb.heaven.util.lang.reflect.ClassTypeUtil; 10 | import com.github.houbb.heaven.util.lang.reflect.ClassUtil; 11 | import com.github.houbb.heaven.util.lang.reflect.ReflectFieldUtil; 12 | 13 | import java.lang.reflect.Field; 14 | import java.util.Collection; 15 | 16 | /** 17 | * 集合读取转换类 18 | * @author binbin.hou 19 | * @since 0.0.3 20 | */ 21 | public class CollectionReadConverter implements IReadConverter { 22 | 23 | @Override 24 | public Collection convert(SingleReadContext context) { 25 | final String value = context.value(); 26 | final Field field = context.field(); 27 | 28 | final String[] entrys = value.split(CsvConst.SPLIT_OR); 29 | 30 | Collection collection = getCollection(field.getType(), entrys.length); 31 | final Class componentType = ReflectFieldUtil.getComponentType(field); 32 | 33 | final CommonReadConverter readConverter = Instances.singleton(CommonReadConverter.class); 34 | for(String string : entrys) { 35 | final Object object = readConverter.convert(string, componentType, context.escape()); 36 | collection.add(object); 37 | } 38 | return collection; 39 | } 40 | 41 | /** 42 | * 根据字段类型获取对应的信息 43 | * (1)list 44 | * (2)set 45 | * (3)其他类型 46 | * @param fieldType 字段类型 47 | * @param size 大小 48 | * @return 结果集合 49 | */ 50 | private Collection getCollection(final Class fieldType, final int size) { 51 | if(ClassTypeUtil.isList(fieldType) 52 | && ClassTypeUtil.isAbstractOrInterface(fieldType)) { 53 | return Guavas.newArrayList(size); 54 | } 55 | 56 | if(ClassTypeUtil.isSet(fieldType) 57 | && ClassTypeUtil.isAbstractOrInterface(fieldType)) { 58 | return Guavas.newHashSet(size); 59 | } 60 | 61 | if(ClassTypeUtil.isAbstractOrInterface(fieldType)) { 62 | throw new UnsupportedOperationException("Only support set or list field component type!"); 63 | } 64 | return (Collection) ClassUtil.newInstance(fieldType); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/collection/MapReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.collection; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.constant.CsvConst; 5 | import com.github.houbb.csv.support.context.SingleReadContext; 6 | import com.github.houbb.csv.support.convert.read.CommonReadConverter; 7 | import com.github.houbb.heaven.response.exception.CommonRuntimeException; 8 | import com.github.houbb.heaven.support.instance.impl.Instances; 9 | import com.github.houbb.heaven.util.guava.Guavas; 10 | import com.github.houbb.heaven.util.lang.StringUtil; 11 | import com.github.houbb.heaven.util.lang.reflect.ClassTypeUtil; 12 | import com.github.houbb.heaven.util.lang.reflect.ReflectFieldUtil; 13 | import com.github.houbb.heaven.util.util.ArrayUtil; 14 | 15 | import java.lang.reflect.Field; 16 | import java.util.Collections; 17 | import java.util.Map; 18 | 19 | /** 20 | * Map 读取转换类 21 | * @author binbin.hou 22 | * @since 0.0.3 23 | */ 24 | public class MapReadConverter implements IReadConverter { 25 | 26 | @Override 27 | public Map convert(SingleReadContext context) { 28 | final String value = context.value(); 29 | final Field field = context.field(); 30 | 31 | //entry 32 | String[] entryStrings = value.split(CsvConst.SPLIT_OR); 33 | if(ArrayUtil.isEmpty(entryStrings)) { 34 | return Collections.emptyMap(); 35 | } 36 | 37 | // 获取对应的 map 实例 38 | final Map map = getMap(field, entryStrings.length); 39 | 40 | final Class keyType = ReflectFieldUtil.getComponentType(field, 0); 41 | final Class valueType = ReflectFieldUtil.getComponentType(field, 1); 42 | 43 | final CommonReadConverter readConverter = Instances.singleton(CommonReadConverter.class); 44 | 45 | for(String entryStr : entryStrings) { 46 | if(StringUtil.isEmpty(entryStr)) { 47 | continue; 48 | } 49 | 50 | String[] kvs = entryStr.split(CsvConst.EQUALS); 51 | if(ArrayUtil.isEmpty(kvs)) { 52 | continue; 53 | } 54 | 55 | Object keyObj = readConverter.convert(kvs[0], keyType, context.escape()); 56 | Object valueObj = readConverter.convert(kvs[1], valueType, context.escape()); 57 | map.put(keyObj, valueObj); 58 | } 59 | 60 | return map; 61 | } 62 | 63 | /** 64 | * 获取对应的 map 65 | * @param field 字段信息 66 | * @param size 大小 67 | * @return map 68 | */ 69 | private Map getMap(final Field field, 70 | final int size) { 71 | final Class fieldType = field.getType(); 72 | 73 | // 抽象类: 暂时只支持 hashMap 74 | if(ClassTypeUtil.isAbstractOrInterface(fieldType)) { 75 | return Guavas.newHashMap(size); 76 | } 77 | 78 | try { 79 | return (Map) fieldType.newInstance(); 80 | } catch (InstantiationException | IllegalAccessException e) { 81 | throw new CommonRuntimeException(e); 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/entry/EntryReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.entry; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.csv.api.IReadConverter; 5 | import com.github.houbb.csv.support.context.SingleReadContext; 6 | import com.github.houbb.csv.support.convert.mapping.ReadMappingConverter; 7 | import com.github.houbb.csv.support.convert.read.CommonReadConverter; 8 | import com.github.houbb.csv.util.CsvFieldUtil; 9 | import com.github.houbb.heaven.annotation.ThreadSafe; 10 | import com.github.houbb.heaven.reflect.model.FieldBean; 11 | import com.github.houbb.heaven.response.exception.CommonRuntimeException; 12 | import com.github.houbb.heaven.support.instance.impl.InstanceFactory; 13 | import com.github.houbb.heaven.support.sort.ISort; 14 | import com.github.houbb.heaven.util.lang.StringUtil; 15 | import com.github.houbb.heaven.util.lang.reflect.ClassUtil; 16 | import com.github.houbb.heaven.util.util.CollectionUtil; 17 | 18 | import java.lang.reflect.Field; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | /** 23 | * 针对单个对象的信息读取 24 | * 25 | * @author binbin.hou 26 | * @since 0.0.4 27 | */ 28 | @ThreadSafe 29 | public class EntryReadConverter implements IReadConverter { 30 | 31 | @Override 32 | public T convert(SingleReadContext context) { 33 | //1. 基础信息 34 | final Class clazz = context.classType(); 35 | final String csvLine = context.value(); 36 | final ISort sort = context.sort(); 37 | final String split = context.split(); 38 | 39 | Map readMapping = CsvFieldUtil.getReadMapping(clazz, sort); 40 | 41 | // 设置对象内容 42 | T instance = (T) ClassUtil.newInstance(clazz); 43 | List stringList = splitCsvLine(csvLine, split); 44 | 45 | // 长度判断(选择二者的最小值) 46 | final int minSize = getMinSize(stringList.size(), readMapping.size()); 47 | try { 48 | for (int i = 0; i < minSize; i++) { 49 | final String value = stringList.get(i); 50 | final Field field = readMapping.get(i).field(); 51 | 52 | final Object object = convertReadValue(value, field, context); 53 | field.set(instance, object); 54 | } 55 | 56 | return instance; 57 | } catch (IllegalAccessException e) { 58 | throw new CommonRuntimeException(e); 59 | } 60 | } 61 | 62 | /** 63 | * 分隔 csv 64 | * 65 | * @param line 原始行 66 | * @param split 分隔符 67 | * @return 字符串列表 68 | */ 69 | private List splitCsvLine(final String line, final String split) { 70 | String fitLine = line; 71 | 72 | // 如果是逗号结尾,需要添加空格。避免 split 缺失问题。 73 | if (fitLine.endsWith(split)) { 74 | fitLine = fitLine + StringUtil.BLANK; 75 | } 76 | 77 | String[] strings = fitLine.split(split); 78 | return CollectionUtil.arrayToList(strings); 79 | } 80 | 81 | /** 82 | * 对读取的内容信息进行转换 83 | * 84 | * @param csvContent csv 文件信息 85 | * @param field 字段信息 86 | * @param oldContext 原始的上下文,避免过多的参数传入 87 | * @return 转换后的对象 88 | */ 89 | private Object convertReadValue(final String csvContent, final Field field, 90 | final SingleReadContext oldContext) { 91 | try { 92 | SingleReadContext context = SingleReadContext.newInstance() 93 | .value(csvContent) 94 | .field(field) 95 | .split(oldContext.split()) 96 | .sort(oldContext.sort()) 97 | .escape(oldContext.escape()); 98 | 99 | // 指定转换器的处理 100 | if (field.isAnnotationPresent(Csv.class)) { 101 | Csv csv = field.getAnnotation(Csv.class); 102 | context.csv(csv); 103 | Class readConverterClass = csv.readConverter(); 104 | 105 | // 优先使用 readMapping 106 | String readMapping = csv.readMapping(); 107 | if(StringUtil.isNotEmpty(readMapping) 108 | && field.getType().equals(String.class)) { 109 | readConverterClass = ReadMappingConverter.class; 110 | } 111 | 112 | return readConverterClass.newInstance().convert(context); 113 | } 114 | 115 | // 通用转换器的处理 116 | return InstanceFactory.getInstance() 117 | .singleton(CommonReadConverter.class) 118 | .convert(context); 119 | 120 | } catch (InstantiationException | IllegalAccessException e) { 121 | throw new CommonRuntimeException(e); 122 | } 123 | } 124 | 125 | /** 126 | * 获取最小的大小 127 | * 128 | * @param sizeOne 大小1 129 | * @param sizeTwo 大小2 130 | * @return 结果 131 | */ 132 | private int getMinSize(final int sizeOne, final int sizeTwo) { 133 | return sizeOne > sizeTwo ? sizeTwo : sizeOne; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/ITypeConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type; 2 | 3 | /** 4 | * 根据类型进行转换 5 | * @author binbin.hou 6 | * @since 0.0.3 7 | * @param 泛型 8 | */ 9 | public interface ITypeConverter { 10 | 11 | /** 12 | * 执行转换 13 | * @param value 字符串值 14 | * @param type 字段类型 15 | * @return 结果 16 | */ 17 | T convert(final String value, final Class type); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/BooleanReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Boolean 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class BooleanReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Boolean convert(String value, Class type) { 16 | return Boolean.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/ByteReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Byte 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class ByteReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Byte convert(String value, final Class type) { 16 | return Byte.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/CharacterReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Character 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class CharacterReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Character convert(String value, final Class type) { 16 | return value.charAt(0); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/DoubleReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Double 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class DoubleReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Double convert(String value, final Class type) { 16 | return Double.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/FloatReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Float 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class FloatReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Float convert(String value, final Class type) { 16 | return Float.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/IntegerReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Integer 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class IntegerReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Integer convert(String value, final Class type) { 16 | return Integer.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/LongReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Long 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class LongReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Long convert(String value,final Class type) { 16 | return Long.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/ShortReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * Short 读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class ShortReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public Short convert(String value, final Class type) { 16 | return Short.valueOf(value); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/StringReadConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; 2 | 3 | import com.github.houbb.csv.support.convert.read.type.ITypeConverter; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | /** 7 | * 字符串读取转换器 8 | * @author binbin.hou 9 | * @since 0.0.1 10 | */ 11 | @ThreadSafe 12 | public class StringReadConverter implements ITypeConverter { 13 | 14 | @Override 15 | public String convert(String value, final Class type) { 16 | return value; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/impl/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type.impl; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/read/type/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.read.type; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/CommonWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.support.context.SingleWriteContext; 5 | import com.github.houbb.csv.support.convert.write.collection.ArrayWriteConverter; 6 | import com.github.houbb.csv.support.convert.write.collection.CollectionWriteConverter; 7 | import com.github.houbb.csv.support.convert.write.collection.MapWriteConverter; 8 | import com.github.houbb.csv.support.convert.write.entry.EntryWriteConverter; 9 | import com.github.houbb.csv.util.CsvFieldUtil; 10 | import com.github.houbb.csv.util.CsvInnerUtil; 11 | import com.github.houbb.heaven.support.instance.impl.Instances; 12 | import com.github.houbb.heaven.util.lang.ObjectUtil; 13 | import com.github.houbb.heaven.util.lang.StringUtil; 14 | import com.github.houbb.heaven.util.lang.reflect.ClassTypeUtil; 15 | 16 | /** 17 | * 通用的写入转换类 18 | * (1)除了集合类 map/array/collection 单独处理 19 | * (2)其他类直接使用 {@link com.github.houbb.heaven.util.lang.StringUtil#objectToString(Object, String)} 转为字符串 20 | * @author binbin.hou 21 | * @since 0.0.3 22 | * @see com.github.houbb.csv.support.convert.read.CommonReadConverter 读取转换对应 23 | */ 24 | public class CommonWriteConverter implements IWriteConverter { 25 | 26 | @Override 27 | public String convert(SingleWriteContext context) { 28 | final Object value = context.value(); 29 | if(ObjectUtil.isNull(value)) { 30 | return StringUtil.EMPTY; 31 | } 32 | 33 | final Class type = value.getClass(); 34 | // 特殊的集合类型处理 35 | if(ClassTypeUtil.isArray(type)) { 36 | return Instances.singleton(ArrayWriteConverter.class).convert(context); 37 | } 38 | if(ClassTypeUtil.isMap(type)) { 39 | return Instances.singleton(MapWriteConverter.class).convert(context); 40 | } 41 | if(ClassTypeUtil.isCollection(type)) { 42 | return Instances.singleton(CollectionWriteConverter.class).convert(context); 43 | } 44 | 45 | // 当前字段指定为 @CsvEntry 且为对象 46 | if(CsvFieldUtil.isEntryAble(context.field())) { 47 | final String split = CsvInnerUtil.getNextSplit(context.split()); 48 | SingleWriteContext singleWriteContext = SingleWriteContext.newInstance() 49 | .sort(context.sort()) 50 | .element(context.value()) 51 | .split(split) 52 | .escape(context.escape()); 53 | return Instances.singleton(EntryWriteConverter.class).convert(singleWriteContext); 54 | } 55 | 56 | return Instances.singleton(StringWriteConverter.class).convert(context); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/StringWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.support.context.SingleWriteContext; 5 | import com.github.houbb.csv.util.CsvInnerUtil; 6 | import com.github.houbb.heaven.annotation.ThreadSafe; 7 | import com.github.houbb.heaven.support.handler.IHandler; 8 | import com.github.houbb.heaven.support.tuple.impl.Pair; 9 | import com.github.houbb.heaven.util.lang.StringUtil; 10 | 11 | /** 12 | * 字符串写入转换器 13 | * @author binbin.hou 14 | * @since 0.0.1 15 | */ 16 | @ThreadSafe 17 | public class StringWriteConverter implements IWriteConverter, IHandler, String> { 18 | 19 | @Override 20 | public String convert(SingleWriteContext context) { 21 | Pair pair = Pair.of(context.value(), context.escape()); 22 | return this.handle(pair); 23 | } 24 | 25 | @Override 26 | public String handle(Pair objectBooleanPair) { 27 | final Object value = objectBooleanPair.getValueOne(); 28 | final Boolean escape = objectBooleanPair.getValueTwo(); 29 | 30 | String result = StringUtil.objectToString(value, StringUtil.EMPTY); 31 | // 特殊字符转换 v0.0.6 32 | if(escape) { 33 | result = CsvInnerUtil.replaceAllSpecial(result); 34 | } 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/collection/AbstractCollectionWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write.collection; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | 5 | /** 6 | * 抽象集合写入转换器 7 | * @author binbin.hou 8 | * @since 0.0.6 9 | */ 10 | public abstract class AbstractCollectionWriteConverter implements IWriteConverter { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/collection/ArrayWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write.collection; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.support.context.SingleWriteContext; 5 | import com.github.houbb.csv.support.convert.write.StringWriteConverter; 6 | import com.github.houbb.heaven.annotation.ThreadSafe; 7 | import com.github.houbb.heaven.constant.PunctuationConst; 8 | import com.github.houbb.heaven.support.instance.impl.Instances; 9 | import com.github.houbb.heaven.support.tuple.impl.Pair; 10 | import com.github.houbb.heaven.util.guava.Guavas; 11 | import com.github.houbb.heaven.util.lang.ObjectUtil; 12 | import com.github.houbb.heaven.util.lang.StringUtil; 13 | 14 | import java.util.Collections; 15 | import java.util.List; 16 | 17 | /** 18 | * 数组写入转换器 19 | * @author binbin.hou 20 | * @since 0.0.3 21 | */ 22 | @ThreadSafe 23 | public class ArrayWriteConverter implements IWriteConverter { 24 | 25 | @Override 26 | public String convert(SingleWriteContext context) { 27 | final List stringList = buildStringList(context); 28 | return StringUtil.join(stringList, PunctuationConst.OR); 29 | } 30 | 31 | /** 32 | * 构建字符串列表 33 | * @param context 上下文 34 | * @return 结果列表 35 | * @since 0.0.6 36 | */ 37 | private List buildStringList(SingleWriteContext context) { 38 | final Object value = context.value(); 39 | if(ObjectUtil.isNull(value)) { 40 | return Collections.emptyList(); 41 | } 42 | 43 | final Object[] arrays = (Object[])value; 44 | List stringList = Guavas.newArrayList(arrays.length); 45 | final boolean escape = context.escape(); 46 | for(Object object : arrays) { 47 | final Pair pair = Pair.of(object, escape); 48 | final String string = Instances.singleton(StringWriteConverter.class) 49 | .handle(pair); 50 | stringList.add(string); 51 | } 52 | return stringList; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/collection/CollectionWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write.collection; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.support.context.SingleWriteContext; 5 | import com.github.houbb.csv.support.convert.write.StringWriteConverter; 6 | import com.github.houbb.heaven.annotation.ThreadSafe; 7 | import com.github.houbb.heaven.constant.PunctuationConst; 8 | import com.github.houbb.heaven.support.instance.impl.Instances; 9 | import com.github.houbb.heaven.support.tuple.impl.Pair; 10 | import com.github.houbb.heaven.util.guava.Guavas; 11 | import com.github.houbb.heaven.util.lang.ObjectUtil; 12 | import com.github.houbb.heaven.util.lang.StringUtil; 13 | 14 | import java.util.Collection; 15 | import java.util.Collections; 16 | import java.util.List; 17 | 18 | /** 19 | * 集合写入转换器 20 | * @author binbin.hou 21 | * @since 0.0.3 22 | */ 23 | @ThreadSafe 24 | public class CollectionWriteConverter implements IWriteConverter { 25 | 26 | @Override 27 | public String convert(SingleWriteContext context) { 28 | final List stringList = buildStringList(context); 29 | return StringUtil.join(stringList, PunctuationConst.OR); 30 | } 31 | 32 | /** 33 | * 构建字符串列表 34 | * @param context 上下文 35 | * @return 结果列表 36 | * @since 0.0.6 37 | */ 38 | private List buildStringList(SingleWriteContext context) { 39 | final Object value = context.value(); 40 | if(ObjectUtil.isNull(value)) { 41 | return Collections.emptyList(); 42 | } 43 | 44 | final Collection collection = (Collection)context.value(); 45 | List stringList = Guavas.newArrayList(collection.size()); 46 | final boolean escape = context.escape(); 47 | for(Object object : collection) { 48 | final Pair pair = Pair.of(object, escape); 49 | final String string = Instances.singleton(StringWriteConverter.class) 50 | .handle(pair); 51 | stringList.add(string); 52 | } 53 | return stringList; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/collection/MapWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write.collection; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.constant.CsvConst; 5 | import com.github.houbb.csv.support.context.SingleWriteContext; 6 | import com.github.houbb.csv.support.convert.write.StringWriteConverter; 7 | import com.github.houbb.heaven.annotation.ThreadSafe; 8 | import com.github.houbb.heaven.constant.PunctuationConst; 9 | import com.github.houbb.heaven.support.instance.impl.Instances; 10 | import com.github.houbb.heaven.support.tuple.impl.Pair; 11 | import com.github.houbb.heaven.util.guava.Guavas; 12 | import com.github.houbb.heaven.util.lang.ObjectUtil; 13 | import com.github.houbb.heaven.util.lang.StringUtil; 14 | 15 | import java.util.*; 16 | 17 | /** 18 | * MAP 写入转换器 19 | * 20 | * @author binbin.hou 21 | * @since 0.0.3 22 | */ 23 | @ThreadSafe 24 | public class MapWriteConverter implements IWriteConverter { 25 | 26 | @Override 27 | public String convert(SingleWriteContext context) { 28 | final List stringList = buildStringList(context); 29 | return StringUtil.join(stringList, PunctuationConst.OR); 30 | } 31 | 32 | /** 33 | * 构建字符串列表 34 | * 35 | * @param context 上下文 36 | * @return 结果列表 37 | * @since 0.0.6 38 | */ 39 | private List buildStringList(SingleWriteContext context) { 40 | final Object value = context.value(); 41 | if (ObjectUtil.isNull(value)) { 42 | return Collections.emptyList(); 43 | } 44 | 45 | final Map map = (Map) context.value(); 46 | List stringList = Guavas.newArrayList(map.size()); 47 | final boolean escape = context.escape(); 48 | // 这里直接使用 entry 会提示错误,暂时使用 key 代替。 49 | for (Object key : map.keySet()) { 50 | final Pair keyPair = Pair.of(key, escape); 51 | final Pair valuePair = Pair.of(map.get(key), escape); 52 | final String keyString = Instances.singleton(StringWriteConverter.class) 53 | .handle(keyPair); 54 | final String valueString = Instances.singleton(StringWriteConverter.class) 55 | .handle(valuePair); 56 | final String string = keyString + CsvConst.EQUALS + valueString; 57 | stringList.add(string); 58 | } 59 | return stringList; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/entry/EntryWriteConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write.entry; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.csv.api.IWriteConverter; 5 | import com.github.houbb.csv.constant.CsvConst; 6 | import com.github.houbb.csv.constant.CsvOperateType; 7 | import com.github.houbb.csv.support.context.SingleWriteContext; 8 | import com.github.houbb.csv.support.convert.mapping.WriteMappingConverter; 9 | import com.github.houbb.csv.support.convert.write.CommonWriteConverter; 10 | import com.github.houbb.csv.util.CsvFieldUtil; 11 | import com.github.houbb.csv.util.CsvInnerUtil; 12 | import com.github.houbb.heaven.annotation.ThreadSafe; 13 | import com.github.houbb.heaven.reflect.model.FieldBean; 14 | import com.github.houbb.heaven.response.exception.CommonRuntimeException; 15 | import com.github.houbb.heaven.support.instance.impl.Instances; 16 | import com.github.houbb.heaven.util.guava.Guavas; 17 | import com.github.houbb.heaven.util.lang.ObjectUtil; 18 | import com.github.houbb.heaven.util.lang.StringUtil; 19 | import com.github.houbb.heaven.util.util.CollectionUtil; 20 | import com.github.houbb.heaven.util.util.Optional; 21 | 22 | import java.util.List; 23 | 24 | /** 25 | * 针对单个对象的信息构建 26 | * (1)必须为对象 27 | * (2)必须为用户自定义对象 28 | *

29 | * 1. array 30 | * 2. 集合 31 | * 3. map 32 | * 4. 对象 33 | * 5. 其他对象 34 | * 35 | * @author binbin.hou 36 | * @since 0.0.4 37 | */ 38 | @ThreadSafe 39 | public class EntryWriteConverter implements IWriteConverter { 40 | 41 | @Override 42 | public String convert(SingleWriteContext context) { 43 | final Object value = context.element(); 44 | if (ObjectUtil.isNull(value)) { 45 | return StringUtil.EMPTY; 46 | } 47 | 48 | // 获取字段信息 49 | Class clazz = value.getClass(); 50 | List fieldBeanList = CsvFieldUtil.getSortedFields(clazz, context.sort(), CsvOperateType.WRITE); 51 | if (CollectionUtil.isEmpty(fieldBeanList)) { 52 | return StringUtil.EMPTY; 53 | } 54 | 55 | return buildWriteLine(context, value, fieldBeanList); 56 | } 57 | 58 | /** 59 | * 构建待写行 60 | * 1. 将需要写入的字段内容用逗号分隔。 61 | * 62 | * @param context 上下文 63 | * @param t 元素 64 | * @param fieldBeans 字段列表 65 | * @return 结果 66 | */ 67 | private String buildWriteLine(final SingleWriteContext context, 68 | final Object t, final List fieldBeans) { 69 | if (ObjectUtil.isNull(t)) { 70 | return StringUtil.EMPTY; 71 | } 72 | 73 | List stringList = Guavas.newArrayList(fieldBeans.size()); 74 | // 默认使用通用转换 75 | IWriteConverter converter = Instances.singleton(CommonWriteConverter.class); 76 | try { 77 | for (FieldBean bean : fieldBeans) { 78 | final Object object = bean.field().get(t); 79 | // 上下文的处理 80 | SingleWriteContext entryContext = SingleWriteContext.newInstance() 81 | .value(object) 82 | .field(bean.field()) 83 | .element(t) 84 | .sort(context.sort()) 85 | .split(CsvConst.COMMA) 86 | .escape(context.escape()); 87 | 88 | final Optional csvOptional = bean.annotationOptByType(Csv.class); 89 | if (csvOptional.isPresent()) { 90 | Csv csv = csvOptional.get(); 91 | entryContext.csv(csv); 92 | converter = csv.writeConverter().newInstance(); 93 | 94 | // 优先使用 writeMapping 95 | if(StringUtil.isNotEmpty(csv.writeMapping()) 96 | && (object instanceof String)) { 97 | converter = new WriteMappingConverter(); 98 | } 99 | } 100 | 101 | String string = converter.convert(entryContext); 102 | stringList.add(string); 103 | } 104 | } catch (InstantiationException | IllegalAccessException e) { 105 | throw new CommonRuntimeException(e); 106 | } 107 | 108 | return CollectionUtil.join(stringList, context.split()); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/convert/write/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.convert.write; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/csv/DefaultCsv.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.csv; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.csv.api.ICsv; 5 | import com.github.houbb.csv.api.IReadContext; 6 | import com.github.houbb.csv.api.IWriteContext; 7 | import com.github.houbb.csv.constant.CsvConst; 8 | import com.github.houbb.csv.constant.CsvOperateType; 9 | import com.github.houbb.csv.support.context.SingleReadContext; 10 | import com.github.houbb.csv.support.context.SingleWriteContext; 11 | import com.github.houbb.csv.support.convert.read.entry.EntryReadConverter; 12 | import com.github.houbb.csv.support.convert.write.entry.EntryWriteConverter; 13 | import com.github.houbb.csv.support.writer.ICsvWriter; 14 | import com.github.houbb.csv.support.writer.impl.CsvWriterContext; 15 | import com.github.houbb.csv.util.CsvFieldUtil; 16 | import com.github.houbb.heaven.annotation.ThreadSafe; 17 | import com.github.houbb.heaven.constant.PunctuationConst; 18 | import com.github.houbb.heaven.reflect.model.FieldBean; 19 | import com.github.houbb.heaven.util.guava.Guavas; 20 | import com.github.houbb.heaven.util.lang.StringUtil; 21 | import com.github.houbb.heaven.util.util.CollectionUtil; 22 | import com.github.houbb.heaven.util.util.MapUtil; 23 | import com.github.houbb.heaven.util.util.Optional; 24 | 25 | import java.util.Collection; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | /** 31 | * 默认的 csv 处理实现 32 | * 33 | * @param 泛型 34 | * @author binbin.hou 35 | * @since 0.0.1 36 | */ 37 | @ThreadSafe 38 | public class DefaultCsv implements ICsv { 39 | 40 | @Override 41 | public List write(IWriteContext context) { 42 | final List writeList = context.list(); 43 | if (CollectionUtil.isEmpty(writeList)) { 44 | return Collections.emptyList(); 45 | } 46 | final Optional firstOpt = CollectionUtil.firstNotNullElem(writeList); 47 | if (firstOpt.isNotPresent()) { 48 | return Collections.emptyList(); 49 | } 50 | final T elem = firstOpt.get(); 51 | final List fieldBeanList = CsvFieldUtil.getSortedFields(elem.getClass(), 52 | context.sort(), CsvOperateType.WRITE); 53 | if (CollectionUtil.isEmpty(fieldBeanList)) { 54 | return Collections.emptyList(); 55 | } 56 | 57 | // 2.1 存储字符串列表 58 | final int size = context.list().size(); 59 | List list = Guavas.newArrayList(size); 60 | 61 | // 2.2 构建每一行的内容 62 | EntryWriteConverter entryWriteConverter = new EntryWriteConverter(); 63 | SingleWriteContext singleWriteContext = SingleWriteContext.newInstance() 64 | .sort(context.sort()) 65 | .escape(context.escape()) 66 | .split(CsvConst.COMMA); 67 | for (T t : writeList) { 68 | singleWriteContext.element(t); 69 | 70 | final String writeLine = entryWriteConverter.convert(singleWriteContext); 71 | if (StringUtil.isEmpty(writeLine)) { 72 | continue; 73 | } 74 | list.add(writeLine); 75 | } 76 | 77 | // 2.3 处理字符串列表 78 | final ICsvWriter csvWriter = context.writer(); 79 | final CsvWriterContext csvWriterContext = CsvWriterContext.newInstance() 80 | .writeBom(context.writeBom()) 81 | .writeHead(context.writeHead()) 82 | .list(list); 83 | 84 | // 2.4 写入头信息 85 | final boolean needWriteHead = context.writeHead(); 86 | if (needWriteHead) { 87 | // 只有需要写入时,才进行计算。 88 | String headLine = buildWriteHead(fieldBeanList); 89 | csvWriterContext.head(headLine); 90 | } 91 | 92 | //2.5 执行写入 93 | csvWriter.write(csvWriterContext); 94 | 95 | //3. 返回结果列表 96 | return list; 97 | } 98 | 99 | /** 100 | * 构建表头 101 | * (1)指定注解,且 label 不为空,则使用 label 102 | * (2)使用 field.name() 103 | *

104 | * 所有字段 label 通过逗号连接。 105 | * 106 | * @param fieldBeanList 元素列表 107 | * @return 对应的 head 字符串 108 | */ 109 | private String buildWriteHead(List fieldBeanList) { 110 | Collection headList = Guavas.newArrayList(fieldBeanList.size()); 111 | 112 | for (FieldBean bean : fieldBeanList) { 113 | String name = bean.name(); 114 | Optional csvOptional = bean.annotationOptByType(Csv.class); 115 | if (csvOptional.isPresent()) { 116 | String label = csvOptional.get().label(); 117 | if (StringUtil.isNotEmpty(label)) { 118 | name = label; 119 | } 120 | } 121 | 122 | headList.add(name); 123 | } 124 | return StringUtil.join(headList, PunctuationConst.COMMA); 125 | } 126 | 127 | @Override 128 | public List read(IReadContext context) { 129 | // 1. 构建字段和下标之间的映射关系。 130 | Map readMapping = CsvFieldUtil.getReadMapping(context.readClass(), context.sort()); 131 | if (MapUtil.isEmpty(readMapping)) { 132 | return Collections.emptyList(); 133 | } 134 | 135 | //2. 文件内容 136 | List allLines = context.reader().read(); 137 | List readableLines = CollectionUtil.subList(allLines, 138 | context.startIndex(), context.endIndex()); 139 | if (CollectionUtil.isEmpty(readableLines)) { 140 | return Collections.emptyList(); 141 | } 142 | 143 | //3. 映射处理 144 | List list = Guavas.newArrayList(readableLines.size()); 145 | final Class readClass = context.readClass(); 146 | final EntryReadConverter readConverter = new EntryReadConverter<>(); 147 | 148 | // 单行的上下文,使用同一个对象,节约内存及堆开销 149 | SingleReadContext singleReadContext = new SingleReadContext(); 150 | singleReadContext 151 | .classType(readClass) 152 | .sort(context.sort()) 153 | .split(CsvConst.COMMA) 154 | .escape(context.escape()); 155 | for (String line : readableLines) { 156 | // 跳过空白行 157 | if (StringUtil.isEmpty(line)) { 158 | continue; 159 | } 160 | 161 | // 设置对象内容 162 | singleReadContext.value(line); 163 | T instance = readConverter.convert(singleReadContext); 164 | list.add(instance); 165 | } 166 | return list; 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/csv/DefaultStringListCsv.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.csv; 2 | 3 | import com.github.houbb.csv.api.ICsv; 4 | import com.github.houbb.csv.api.IReadContext; 5 | import com.github.houbb.csv.api.IWriteContext; 6 | import com.github.houbb.csv.support.writer.ICsvWriter; 7 | import com.github.houbb.csv.support.writer.impl.CsvWriterContext; 8 | import com.github.houbb.heaven.annotation.ThreadSafe; 9 | import com.github.houbb.heaven.util.guava.Guavas; 10 | import com.github.houbb.heaven.util.lang.StringUtil; 11 | import com.github.houbb.heaven.util.util.CollectionUtil; 12 | 13 | import java.util.*; 14 | import java.util.regex.Matcher; 15 | import java.util.regex.Pattern; 16 | 17 | /** 18 | * 处理为 list 19 | * 20 | * @author binbin.hou 21 | * @since 0.2.0 22 | */ 23 | @ThreadSafe 24 | public class DefaultStringListCsv implements ICsv> { 25 | 26 | @Override 27 | public List write(IWriteContext> context) { 28 | final List> writeList = context.list(); 29 | if (CollectionUtil.isEmpty(writeList) 30 | || writeList.size() <= 0) { 31 | return Collections.emptyList(); 32 | } 33 | 34 | // 2.1 存储字符串列表 35 | final int size = context.list().size(); 36 | List list = Guavas.newArrayList(size); 37 | 38 | // 2.2 构建每一行的内容 39 | final char quoteChar = context.quoteChar(); 40 | for (int i = 1; i < writeList.size(); i++) { 41 | List t = writeList.get(i); 42 | 43 | String writeLine = joinCsvLine(t, quoteChar); 44 | if (StringUtil.isEmpty(writeLine)) { 45 | continue; 46 | } 47 | list.add(writeLine); 48 | } 49 | 50 | // 2.3 处理字符串列表 51 | final ICsvWriter csvWriter = context.writer(); 52 | final CsvWriterContext csvWriterContext = CsvWriterContext.newInstance() 53 | .writeBom(context.writeBom()) 54 | .writeHead(context.writeHead()) 55 | .list(list); 56 | 57 | // 2.4 写入头信息 58 | final boolean needWriteHead = context.writeHead(); 59 | if (needWriteHead) { 60 | // 只有需要写入时,才进行计算。 61 | String headLine = joinCsvLine(writeList.get(0), quoteChar); 62 | csvWriterContext.head(headLine); 63 | } 64 | 65 | //2.5 执行写入 66 | csvWriter.write(csvWriterContext); 67 | 68 | //3. 返回结果列表 69 | return list; 70 | } 71 | 72 | @Override 73 | public List> read(IReadContext> context) { 74 | //2. 文件内容 75 | List allLines = context.reader().read(); 76 | List readableLines = CollectionUtil.subList(allLines, 77 | context.startIndex(), context.endIndex()); 78 | if (CollectionUtil.isEmpty(readableLines)) { 79 | return Collections.emptyList(); 80 | } 81 | 82 | final char quoteChar = context.quoteChar(); 83 | List> resultList = new ArrayList<>(); 84 | for (String line : readableLines) { 85 | // 跳过空白行 86 | if (StringUtil.isEmpty(line)) { 87 | continue; 88 | } 89 | 90 | // 设置对象内容 91 | List lineSplit = splitCsvLine(line, quoteChar); 92 | resultList.add(lineSplit); 93 | } 94 | 95 | return resultList; 96 | } 97 | 98 | protected String joinCsvLine(List splitList, char quoteChar) { 99 | //fast-fail 100 | if(CollectionUtil.isEmpty(splitList)) { 101 | return ""; 102 | } 103 | 104 | StringBuilder stringBuilder = new StringBuilder(); 105 | 106 | 107 | for(int i = 0; i < splitList.size()-1; i++) { 108 | String field = splitList.get(i); 109 | String escapedField = getJoinEscapeField(field, quoteChar); 110 | 111 | stringBuilder.append(escapedField) 112 | .append(","); 113 | } 114 | 115 | String lastField = splitList.get(splitList.size()-1); 116 | String escapedField = getJoinEscapeField(lastField, quoteChar); 117 | stringBuilder.append(escapedField); 118 | return stringBuilder.toString(); 119 | } 120 | 121 | protected String getJoinEscapeField(String field, char quoteChar) { 122 | if(field.contains(",")) { 123 | return quoteChar + field + quoteChar; 124 | } 125 | return field; 126 | } 127 | 128 | protected List splitCsvLine(String csvData, char quoteChar) { 129 | List result = new ArrayList<>(); 130 | 131 | // 定义 CSV 数据的正则表达式 132 | String regex = "(?:" + // 开始非捕获组 133 | "([^" + quoteChar + ",]+)" + // 匹配非引号非逗号的内容 134 | "|\"" + // 或匹配引号开头的内容 135 | "([^" + quoteChar + "]*)\"" + // 匹配引号中的内容 136 | ")"; 137 | 138 | Pattern pattern = Pattern.compile(regex); 139 | Matcher matcher = pattern.matcher(csvData); 140 | 141 | while (matcher.find()) { 142 | String field = matcher.group(1) != null ? matcher.group(1) : matcher.group(2); 143 | result.add(field); 144 | } 145 | 146 | return result; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/csv/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.csv; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/ICsvReader.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader; 2 | 3 | import com.github.houbb.heaven.annotation.CommonEager; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 可以抽象为 readers 9 | * 10 | * 1. readString 11 | * 2. readLines 12 | * @author binbin.hou 13 | * @since 0.0.8 14 | */ 15 | @CommonEager 16 | public interface ICsvReader { 17 | 18 | /** 19 | * 读取内容 20 | * @return 结果 21 | * @since 0.0.8 22 | */ 23 | List read(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/impl/CsvReaderFile.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader.impl; 2 | 3 | import com.github.houbb.csv.support.reader.ICsvReader; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | import com.github.houbb.heaven.constant.CharsetConst; 6 | import com.github.houbb.heaven.util.io.FileUtil; 7 | 8 | import java.io.File; 9 | import java.util.List; 10 | 11 | /** 12 | * @author binbin.hou 13 | * @since 0.0.8 14 | */ 15 | @ThreadSafe 16 | public class CsvReaderFile implements ICsvReader { 17 | 18 | /** 19 | * 文件信息 20 | * @since 0.0.8 21 | */ 22 | private final File file; 23 | 24 | /** 25 | * 文件编码 26 | * @since 0.0.8 27 | */ 28 | private final String charset; 29 | 30 | public CsvReaderFile(File file, String charset) { 31 | this.file = file; 32 | this.charset = charset; 33 | } 34 | 35 | public CsvReaderFile(File file) { 36 | this(file, CharsetConst.UTF8); 37 | } 38 | 39 | /** 40 | * 读取内容 41 | * 42 | * @return 结果 43 | * @since 0.0.8 44 | */ 45 | @Override 46 | public List read() { 47 | return FileUtil.readAllLines(file, charset); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/impl/CsvReaderFilePath.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader.impl; 2 | 3 | import com.github.houbb.csv.support.reader.ICsvReader; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | import com.github.houbb.heaven.constant.CharsetConst; 6 | import com.github.houbb.heaven.util.io.FileUtil; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author binbin.hou 12 | * @since 0.0.8 13 | */ 14 | @ThreadSafe 15 | public class CsvReaderFilePath implements ICsvReader { 16 | 17 | /** 18 | * 文件路径信息 19 | * @since 0.0.8 20 | */ 21 | private final String filePath; 22 | 23 | /** 24 | * 文件编码 25 | * @since 0.0.8 26 | */ 27 | private final String charset; 28 | 29 | public CsvReaderFilePath(String filePath, String charset) { 30 | this.filePath = filePath; 31 | this.charset = charset; 32 | } 33 | 34 | public CsvReaderFilePath(String filePath) { 35 | this(filePath, CharsetConst.UTF8); 36 | } 37 | 38 | /** 39 | * 读取内容 40 | * 41 | * @return 结果 42 | * @since 0.0.8 43 | */ 44 | @Override 45 | public List read() { 46 | return FileUtil.readAllLines(filePath, charset); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/impl/CsvReaderInputStream.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader.impl; 2 | 3 | import com.github.houbb.csv.support.reader.ICsvReader; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | import com.github.houbb.heaven.constant.CharsetConst; 6 | import com.github.houbb.heaven.util.io.FileUtil; 7 | 8 | import java.io.InputStream; 9 | import java.util.List; 10 | 11 | /** 12 | * 输入流 13 | * @author binbin.hou 14 | * @since 0.0.8 15 | */ 16 | @ThreadSafe 17 | public class CsvReaderInputStream implements ICsvReader { 18 | 19 | /** 20 | * 输入流 21 | * @since 0.0.8 22 | */ 23 | private final InputStream inputStream; 24 | 25 | /** 26 | * 编码 27 | * @since 0.0.8 28 | */ 29 | private final String charset; 30 | 31 | public CsvReaderInputStream(InputStream inputStream, String charset) { 32 | this.inputStream = inputStream; 33 | this.charset = charset; 34 | } 35 | 36 | public CsvReaderInputStream(InputStream inputStream) { 37 | this(inputStream, CharsetConst.UTF8); 38 | } 39 | 40 | /** 41 | * 读取内容 42 | * 43 | * @return 结果 44 | * @since 0.0.8 45 | */ 46 | @Override 47 | public List read() { 48 | return FileUtil.readAllLines(inputStream, charset); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/impl/CsvReaderList.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader.impl; 2 | 3 | import com.github.houbb.csv.support.reader.ICsvReader; 4 | import com.github.houbb.heaven.annotation.ThreadSafe; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author binbin.hou 10 | * @since 0.0.8 11 | */ 12 | @ThreadSafe 13 | public class CsvReaderList implements ICsvReader { 14 | 15 | /** 16 | * 字符串列表 17 | * @since 0.0.8 18 | */ 19 | private final List strings; 20 | 21 | public CsvReaderList(List strings) { 22 | this.strings = strings; 23 | } 24 | 25 | /** 26 | * 读取内容 27 | * 28 | * @return 结果 29 | * @since 0.0.8 30 | */ 31 | @Override 32 | public List read() { 33 | return strings; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/impl/CsvReaders.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader.impl; 2 | 3 | import com.github.houbb.csv.support.reader.ICsvReader; 4 | import com.github.houbb.heaven.annotation.CommonEager; 5 | 6 | import java.io.File; 7 | import java.io.InputStream; 8 | import java.util.List; 9 | 10 | /** 11 | * @author binbin.hou 12 | * @since 0.0.8 13 | */ 14 | @CommonEager 15 | public final class CsvReaders { 16 | 17 | private CsvReaders(){} 18 | 19 | /** 20 | * 基于字符串列表的处理 21 | * @param lines 字符串列表 22 | * @return 结果信息 23 | * @since 0.0.8 24 | */ 25 | public static ICsvReader list(final List lines) { 26 | return new CsvReaderList(lines); 27 | } 28 | 29 | /** 30 | * 基于字符串列表的处理 31 | * @param file 文件信息 32 | * @param charset 文件编码 33 | * @return 结果信息 34 | * @since 0.0.8 35 | */ 36 | public static ICsvReader file(final File file, 37 | final String charset) { 38 | return new CsvReaderFile(file, charset); 39 | } 40 | 41 | /** 42 | * 基于字符串列表的处理 43 | * @param file 文件信息 44 | * @return 结果信息 45 | * @since 0.0.8 46 | */ 47 | public static ICsvReader file(final File file) { 48 | return new CsvReaderFile(file); 49 | } 50 | 51 | /** 52 | * 基于文件路径的处理 53 | * @param file 文件信息 54 | * @param charset 文件编码 55 | * @return 结果信息 56 | * @since 0.0.8 57 | */ 58 | public static ICsvReader filePath(final String file, 59 | final String charset) { 60 | return new CsvReaderFilePath(file, charset); 61 | } 62 | 63 | /** 64 | * 基于文件路径的处理 65 | * @param file 文件信息 66 | * @return 结果信息 67 | * @since 0.0.8 68 | */ 69 | public static ICsvReader filePath(final String file) { 70 | return new CsvReaderFilePath(file); 71 | } 72 | 73 | /** 74 | * 基于文件输入流的处理 75 | * @param inputStream 文件输入流 76 | * @param charset 文件编码 77 | * @return 结果信息 78 | * @since 0.0.8 79 | */ 80 | public static ICsvReader inputStream(final InputStream inputStream, 81 | final String charset) { 82 | return new CsvReaderInputStream(inputStream, charset); 83 | } 84 | 85 | /** 86 | * 基于文件输入流的处理 87 | * @param inputStream 文件输入流 88 | * @return 结果信息 89 | * @since 0.0.8 90 | */ 91 | public static ICsvReader inputStream(final InputStream inputStream) { 92 | return new CsvReaderInputStream(inputStream); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/reader/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.reader; -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/ICsvWriter.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer; 2 | 3 | /** 4 | * @author binbin.hou 5 | * @since 0.0.8 6 | */ 7 | public interface ICsvWriter { 8 | 9 | /** 10 | * 针对字符串列表的写入 11 | * @param context 写入上下文 12 | * @since 0.0.8 13 | */ 14 | void write(final ICsvWriterContext context); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/ICsvWriterContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 写入上下文 7 | * @author binbin.hou 8 | * @since 0.0.9 9 | */ 10 | public interface ICsvWriterContext { 11 | 12 | /** 13 | * 是否写入标题头 14 | * @return 是否写入 head 行 15 | * @since 0.0.9 16 | */ 17 | boolean writeHead(); 18 | 19 | /** 20 | * 是否写入 bom 头 21 | * @return 是否 22 | * @since 0.0.9 23 | */ 24 | boolean writeBom(); 25 | 26 | /** 27 | * 头信息 28 | * @return 头信息 29 | * @since 0.0.9 30 | */ 31 | String head(); 32 | 33 | /** 34 | * 待写入的字符串列表 35 | * @return 列表 36 | * @since 0.0.9 37 | */ 38 | List list(); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/impl/CsvWriterConsole.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer.impl; 2 | 3 | import com.github.houbb.csv.support.writer.ICsvWriter; 4 | import com.github.houbb.csv.support.writer.ICsvWriterContext; 5 | import com.github.houbb.heaven.annotation.ThreadSafe; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 控台输出,主要用于调试和自测 11 | * @author binbin.hou 12 | * @since 0.0.8 13 | */ 14 | @ThreadSafe 15 | public class CsvWriterConsole implements ICsvWriter { 16 | 17 | /** 18 | * 针对字符串列表的写入 19 | * 20 | * @param context 上下文 21 | * @since 0.0.8 22 | */ 23 | @Override 24 | public void write(final ICsvWriterContext context) { 25 | //do nothing 26 | List list = context.list(); 27 | for(String line : list) { 28 | System.out.println(line); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/impl/CsvWriterContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer.impl; 2 | 3 | import com.github.houbb.csv.support.writer.ICsvWriterContext; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author binbin.hou 9 | * @since 0.0.9 10 | */ 11 | public class CsvWriterContext implements ICsvWriterContext { 12 | 13 | /** 14 | * 是否写入标题头 15 | * @since 0.0.9 16 | */ 17 | private boolean writeHead; 18 | 19 | /** 20 | * 是否写入 bom 头 21 | * @since 0.0.9 22 | */ 23 | private boolean writeBom; 24 | 25 | /** 26 | * 头信息 27 | * @since 0.0.9 28 | */ 29 | private String head; 30 | 31 | /** 32 | * 待写入的字符串列表 33 | * @since 0.0.9 34 | */ 35 | private List list; 36 | 37 | /** 38 | * 新建实例 39 | * @return this 40 | * @since 0.0.9 41 | */ 42 | public static CsvWriterContext newInstance() { 43 | return new CsvWriterContext(); 44 | } 45 | 46 | @Override 47 | public boolean writeHead() { 48 | return writeHead; 49 | } 50 | 51 | public CsvWriterContext writeHead(boolean writeHead) { 52 | this.writeHead = writeHead; 53 | return this; 54 | } 55 | 56 | @Override 57 | public boolean writeBom() { 58 | return writeBom; 59 | } 60 | 61 | public CsvWriterContext writeBom(boolean writeBom) { 62 | this.writeBom = writeBom; 63 | return this; 64 | } 65 | 66 | @Override 67 | public String head() { 68 | return head; 69 | } 70 | 71 | public CsvWriterContext head(String head) { 72 | this.head = head; 73 | return this; 74 | } 75 | 76 | @Override 77 | public List list() { 78 | return list; 79 | } 80 | 81 | public CsvWriterContext list(List list) { 82 | this.list = list; 83 | return this; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/impl/CsvWriterFilePath.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer.impl; 2 | 3 | import com.github.houbb.csv.exception.CsvException; 4 | import com.github.houbb.csv.support.writer.ICsvWriter; 5 | import com.github.houbb.csv.support.writer.ICsvWriterContext; 6 | import com.github.houbb.csv.util.CsvBomUtil; 7 | import com.github.houbb.heaven.annotation.ThreadSafe; 8 | import com.github.houbb.heaven.constant.CharsetConst; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.nio.charset.Charset; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.nio.file.Paths; 16 | import java.nio.file.StandardOpenOption; 17 | import java.util.List; 18 | 19 | /** 20 | * 控台输出,主要用于调试和自测 21 | * @author binbin.hou 22 | * @since 0.0.8 23 | */ 24 | @ThreadSafe 25 | public class CsvWriterFilePath implements ICsvWriter { 26 | 27 | /** 28 | * 文件路径 29 | * @since 0.0.8 30 | */ 31 | private final String filePath; 32 | 33 | /** 34 | * 文件编码 35 | * @since 0.0.8 36 | */ 37 | private final String charset; 38 | 39 | public CsvWriterFilePath(String filePath, String charset) { 40 | this.filePath = filePath; 41 | this.charset = charset; 42 | } 43 | 44 | public CsvWriterFilePath(String filePath) { 45 | this(filePath, CharsetConst.UTF8); 46 | } 47 | 48 | /** 49 | * 针对字符串列表的写入 50 | * 51 | * @param context 上下文 52 | * @since 0.0.8 53 | */ 54 | @Override 55 | public void write(final ICsvWriterContext context) { 56 | try { 57 | // 父类文件夹创建 58 | //2. 统一写入文件 59 | // 默认使用添加的方式写入,后期再开放这个开关 60 | Path path = Paths.get(filePath); 61 | //2.1 创建父类文件夹 62 | File parent = path.getParent().toFile(); 63 | if (!parent.exists()) { 64 | boolean result = parent.mkdirs(); 65 | if(!result) { 66 | throw new CsvException("File mkdirs failed!"); 67 | } 68 | } 69 | //2.2 创建文件 70 | File file = path.toFile(); 71 | if (!file.exists()) { 72 | boolean result = file.createNewFile(); 73 | if(!result) { 74 | throw new CsvException("File create failed!"); 75 | } 76 | } 77 | 78 | //2.3 写入(首先记录状态,然后写入信息) 79 | // 2.3.1 写入 bom 头(默认清空文件内容) 80 | // 只有文件为空时才进行写入 81 | final byte[] bomBytes = CsvBomUtil.getBom(charset); 82 | boolean needWriteBoom = context.writeBom() && file.length() <= 0; 83 | if (needWriteBoom) { 84 | Files.write(path, bomBytes, StandardOpenOption.APPEND); 85 | } 86 | 87 | // 2.4 写入头信息 88 | final List writeList = context.list(); 89 | // 只有头信息不存在时,才重复写入头信息。 90 | boolean needWriteHead = context.writeHead() && file.length() <= bomBytes.length; 91 | if(needWriteHead) { 92 | writeList.add(0, context.head()); 93 | } 94 | 95 | //2.5 新增的方式写入内容 96 | Files.write(path, writeList, Charset.forName(charset), StandardOpenOption.APPEND); 97 | } catch (IOException e) { 98 | throw new CsvException(e); 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/impl/CsvWriterNone.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer.impl; 2 | 3 | import com.github.houbb.csv.support.writer.ICsvWriter; 4 | import com.github.houbb.csv.support.writer.ICsvWriterContext; 5 | import com.github.houbb.heaven.annotation.ThreadSafe; 6 | 7 | /** 8 | * @author binbin.hou 9 | * @since 0.0.8 10 | */ 11 | @ThreadSafe 12 | public class CsvWriterNone implements ICsvWriter { 13 | 14 | /** 15 | * 针对字符串列表的写入 16 | * 17 | * @param context 上下文 18 | * @since 0.0.8 19 | */ 20 | @Override 21 | public void write(final ICsvWriterContext context) { 22 | //do nothing 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/support/writer/impl/CsvWriters.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.support.writer.impl; 2 | 3 | import com.github.houbb.csv.support.writer.ICsvWriter; 4 | import com.github.houbb.heaven.constant.CharsetConst; 5 | import com.github.houbb.heaven.support.instance.impl.Instances; 6 | 7 | /** 8 | * 控台输出,主要用于调试和自测 9 | * @author binbin.hou 10 | * @since 0.0.8 11 | */ 12 | public final class CsvWriters { 13 | 14 | private CsvWriters(){} 15 | 16 | /** 17 | * 什么都不做 18 | * @return 实现 19 | * @since 0.0.8 20 | */ 21 | public static ICsvWriter none() { 22 | return Instances.singleton(CsvWriterNone.class); 23 | } 24 | 25 | /** 26 | * 命令行输出 27 | * @return 实现 28 | * @since 0.0.8 29 | */ 30 | public static ICsvWriter console() { 31 | return Instances.singleton(CsvWriterConsole.class); 32 | } 33 | 34 | /** 35 | * 文件输出 36 | * @param filePath 文件路径 37 | * @param charset 文件编码 38 | * @return 实现 39 | * @since 0.0.8 40 | */ 41 | public static ICsvWriter filePath(final String filePath, 42 | final String charset) { 43 | return new CsvWriterFilePath(filePath, charset); 44 | } 45 | 46 | /** 47 | * 文件输出 48 | * @param filePath 文件路径 49 | * @return 实现 50 | * @since 0.0.8 51 | */ 52 | public static ICsvWriter filePath(final String filePath) { 53 | return new CsvWriterFilePath(filePath, CharsetConst.UTF8); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/util/CsvBomUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | /** 6 | * Bom 工具类 7 | * 针对常见的编码 bom 进行整理,避免 windows 打开 csv 乱码。 8 | * 9 | * 注意:一般 windows 默认使用(Little Endian) 10 | * @author binbin.hou 11 | * @since 0.0.4 12 | */ 13 | public final class CsvBomUtil { 14 | 15 | private CsvBomUtil(){} 16 | 17 | /** 18 | * UTF8_BOM 行信息,避免 excel 打开乱码 19 | */ 20 | private static final byte[] UTF8_BOM = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}; 21 | 22 | /** 23 | * UTF-16(大端序) 24 | */ 25 | private static final byte[] UTF16_BIG_BOM = new byte[]{(byte) 0xFE, (byte) 0xFF}; 26 | 27 | /** 28 | * UTF-16(小端序) 29 | */ 30 | private static final byte[] UTF16_LITTLE_BOM = new byte[]{(byte) 0xFF, (byte) 0xFE}; 31 | 32 | /** 33 | * UTF-32(大端序) 34 | */ 35 | private static final byte[] UTF32_BIG_BOM = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF}; 36 | 37 | /** 38 | * UTF-32(小端序) 39 | */ 40 | private static final byte[] UTF32_LITTLE_BOM = new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0x00, (byte) 0x00}; 41 | 42 | /** 43 | * UTF-7 44 | * 2B 2F 76和以下的一个字节:[ 38 | 39 | 2B | 2F ] 45 | */ 46 | private static final byte[] UTF7_BOM = new byte[]{(byte) 0x2B, (byte) 0x2F, (byte) 0x76, (byte) 0x38}; 47 | 48 | 49 | /** 50 | * UTF-1 51 | * F7 64 4C 52 | */ 53 | private static final byte[] UTF1_BOM = new byte[]{(byte) 0xF7, (byte) 0x64, (byte) 0x4C}; 54 | 55 | /** 56 | * en:UTF-EBCDIC 57 | * DD 73 66 73 58 | */ 59 | private static final byte[] UTF_EBCDIC_BOM = new byte[]{(byte) 0xDD, (byte) 0x73, (byte) 0x66, (byte) 0x73}; 60 | 61 | /** 62 | * en:Standard Compression Scheme for Unicode 63 | * 0E FE FF 64 | */ 65 | private static final byte[] SCSFU_BOM = new byte[]{(byte) 0x0E, (byte) 0xFE, (byte) 0xFF}; 66 | 67 | /** 68 | * en:BOCU-1 69 | * FB EE 28及可能跟随着FF 70 | */ 71 | private static final byte[] BOCU1_BOM = new byte[]{(byte) 0xFB, (byte) 0xEE, (byte) 0x28}; 72 | 73 | /** 74 | * GB-18030 75 | * 84 31 95 33 76 | */ 77 | private static final byte[] GB_18030_BOM = new byte[]{(byte) 0x84, (byte) 0x31, (byte) 0x95, (byte) 0x33}; 78 | 79 | /** 80 | * 获取对应的 bom 头 81 | * @param charset 编码 82 | * @return 结果信息 83 | */ 84 | public static byte[] getBom(final String charset) { 85 | if(StandardCharsets.UTF_8.name().equals(charset)) { 86 | return UTF8_BOM; 87 | } 88 | return new byte[]{}; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/util/CsvFieldUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.csv.annotation.CsvEntry; 5 | import com.github.houbb.csv.constant.CsvOperateType; 6 | import com.github.houbb.heaven.constant.PunctuationConst; 7 | import com.github.houbb.heaven.reflect.model.FieldBean; 8 | import com.github.houbb.heaven.support.sort.ISort; 9 | import com.github.houbb.heaven.util.guava.Guavas; 10 | import com.github.houbb.heaven.util.lang.reflect.ClassTypeUtil; 11 | import com.github.houbb.heaven.util.lang.reflect.ClassUtil; 12 | import com.github.houbb.heaven.util.lang.reflect.ReflectFieldUtil; 13 | import com.github.houbb.heaven.util.util.CollectionUtil; 14 | import com.github.houbb.heaven.util.util.MapUtil; 15 | 16 | import java.lang.reflect.Field; 17 | import java.util.Collections; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | 22 | /** 23 | * CSV 字段工具类 24 | * @author binbin.hou 25 | * @since 0.0.4 26 | */ 27 | public final class CsvFieldUtil { 28 | 29 | private CsvFieldUtil(){} 30 | 31 | /** 32 | * 本地缓存 33 | * key: class.fullName + type 34 | */ 35 | private static final Map> CACHE = new ConcurrentHashMap<>(); 36 | 37 | /** 38 | * 获取排序后的字段 39 | * 40 | * @param tClass 类 41 | * @param sort 排序 42 | * @param type 操作方式 43 | * @return 列表 44 | */ 45 | public static List getSortedFields(final Class tClass, 46 | final ISort sort, 47 | final CsvOperateType type) { 48 | final String cacheKey = buildCacheKey(tClass, type); 49 | if(CACHE.containsKey(cacheKey)) { 50 | return CACHE.get(cacheKey); 51 | } 52 | 53 | List resultList = Guavas.newArrayList(); 54 | List allFields = ClassUtil.getAllFieldList(tClass); 55 | if (CollectionUtil.isEmpty(allFields)) { 56 | resultList = Collections.emptyList(); 57 | } 58 | 59 | //sort 60 | List sortedFields = sort.sort(allFields); 61 | 62 | // map 处理 63 | //1. 没有注解,正常处理。 64 | //2. 有注解,但是 require=false 则跳过。 65 | for (Field field : sortedFields) { 66 | Csv csv = null; 67 | if (field.isAnnotationPresent(Csv.class)) { 68 | csv = field.getAnnotation(Csv.class); 69 | if (CsvOperateType.READ.equals(type) 70 | && !csv.readRequire()) { 71 | continue; 72 | } 73 | if (CsvOperateType.WRITE.equals(type) 74 | && !csv.writeRequire()) { 75 | continue; 76 | } 77 | } 78 | 79 | FieldBean fieldBean = new FieldBean(); 80 | fieldBean.field(field) 81 | .name(field.getName()) 82 | .annotation(csv); 83 | //添加到列表中 84 | resultList.add(fieldBean); 85 | } 86 | 87 | // 存放在 cache 中 88 | CACHE.put(cacheKey, resultList); 89 | return resultList; 90 | } 91 | 92 | /** 93 | * 构建缓存 cache 94 | * (1)读写是要区分开的 95 | * String.class, CsvOperateType.READ 96 | * 输出:java.lang.String_READ 97 | * @param tClass 类 98 | * @param type 操作类型 99 | * @return 缓存 key 100 | */ 101 | private static String buildCacheKey(final Class tClass, 102 | final CsvOperateType type) { 103 | return tClass.getName()+ PunctuationConst.UNDERLINE+type.name(); 104 | } 105 | 106 | /** 107 | * 获取读取的映射关系 108 | * 109 | * @param tClass 类 110 | * @param sort 排序信息 111 | * @return 映射关系 112 | */ 113 | public static Map getReadMapping(final Class tClass, 114 | final ISort sort) { 115 | List sortedFields = CsvFieldUtil.getSortedFields(tClass, sort, 116 | CsvOperateType.READ); 117 | 118 | return MapUtil.toIndexMap(sortedFields); 119 | } 120 | 121 | /** 122 | * 是否进行明细相关处理 123 | * @param field 字段信息 124 | * @return 是否 125 | * @since 0.0.5 126 | */ 127 | public static boolean isEntryAble(final Field field) { 128 | return ReflectFieldUtil.isAnnotationPresent(field, CsvEntry.class) 129 | && ClassTypeUtil.isJavaBean(field.getType()); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/util/CsvHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.bs.CsvReadBs; 4 | import com.github.houbb.csv.bs.CsvWriteBs; 5 | import com.github.houbb.csv.constant.CsvConst; 6 | import com.github.houbb.csv.support.reader.ICsvReader; 7 | import com.github.houbb.csv.support.reader.impl.CsvReaders; 8 | import com.github.houbb.csv.support.writer.ICsvWriter; 9 | import com.github.houbb.csv.support.writer.impl.CsvWriters; 10 | import com.github.houbb.heaven.constant.CharsetConst; 11 | 12 | import java.io.File; 13 | import java.io.InputStream; 14 | import java.util.List; 15 | 16 | /** 17 | * csv 读写工具类 18 | * 19 | * @author binbin.hou 20 | * @since 0.0.8 21 | */ 22 | public final class CsvHelper { 23 | 24 | private CsvHelper() { 25 | } 26 | 27 | /** 28 | * 读取文件信息 29 | * 30 | * @param inputStream 文件输入流 31 | * @param tClass 读取类 32 | * @param 泛型 33 | * @return 结果列表 34 | * @since 0.0.8 35 | */ 36 | public static List read(final InputStream inputStream, 37 | final Class tClass) { 38 | final ICsvReader reader = CsvReaders.inputStream(inputStream); 39 | return read(reader, tClass); 40 | } 41 | 42 | /** 43 | * 读取文件信息 44 | * 45 | * @param inputStream 文件输入流 46 | * @param charset 文件编码 47 | * @param tClass 读取类 48 | * @param 泛型 49 | * @return 结果列表 50 | * @since 0.0.8 51 | */ 52 | public static List read(final InputStream inputStream, 53 | final String charset, 54 | final Class tClass) { 55 | final ICsvReader reader = CsvReaders.inputStream(inputStream, charset); 56 | return read(reader, tClass); 57 | } 58 | 59 | /** 60 | * 读取文件信息 61 | * 62 | * @param file 文件 63 | * @param tClass 读取类 64 | * @param 泛型 65 | * @return 结果列表 66 | * @since 0.0.8 67 | */ 68 | public static List read(final File file, 69 | final Class tClass) { 70 | final ICsvReader reader = CsvReaders.file(file); 71 | return read(reader, tClass); 72 | } 73 | 74 | /** 75 | * 读取文件信息 76 | * 77 | * @param file 文件 78 | * @param charset 字符编码 79 | * @param tClass 读取类 80 | * @param 泛型 81 | * @return 结果列表 82 | * @since 0.0.8 83 | */ 84 | public static List read(final File file, 85 | final String charset, 86 | final Class tClass) { 87 | final ICsvReader reader = CsvReaders.file(file, charset); 88 | return read(reader, tClass); 89 | } 90 | 91 | /** 92 | * 读取文件信息 93 | * 94 | * @param filePath 文件路径 95 | * @param tClass 读取类 96 | * @param 泛型 97 | * @return 结果列表 98 | * @since 0.0.8 99 | */ 100 | public static List read(final String filePath, 101 | final Class tClass) { 102 | final ICsvReader reader = CsvReaders.filePath(filePath); 103 | return read(reader, tClass); 104 | } 105 | 106 | /** 107 | * 读取文件信息 108 | * 109 | * @param filePath 文件路径 110 | * @param charset 字符编码 111 | * @param tClass 读取类 112 | * @param 泛型 113 | * @return 结果列表 114 | * @since 0.0.8 115 | */ 116 | public static List read(final String filePath, 117 | final String charset, 118 | final Class tClass) { 119 | final ICsvReader reader = CsvReaders.filePath(filePath, charset); 120 | return read(reader, tClass); 121 | } 122 | 123 | /** 124 | * 读取文件信息 125 | * 126 | * @param stringList 字符串列表 127 | * @param tClass 读取类 128 | * @param 泛型 129 | * @return 结果列表 130 | * @since 0.0.8 131 | */ 132 | public static List read(final List stringList, 133 | final Class tClass) { 134 | final ICsvReader reader = CsvReaders.list(stringList); 135 | return read(reader, tClass); 136 | } 137 | 138 | /** 139 | * 读取文件信息 140 | * 141 | * @param csvReader csv 读取类 142 | * @param tClass 读取类 143 | * @param 泛型 144 | * @return 结果列表 145 | * @since 0.0.8 146 | */ 147 | public static List read(final ICsvReader csvReader, 148 | final Class tClass) { 149 | return read(csvReader, tClass, CsvConst.DEFAULT_START_INDEX); 150 | } 151 | 152 | /** 153 | * 读取文件信息 154 | * 155 | * @param csvReader csv 读取类 156 | * @param tClass 读取类 157 | * @param startIndex 开始下标 158 | * @param 泛型 159 | * @return 结果列表 160 | * @since 0.0.8 161 | */ 162 | public static List read(final ICsvReader csvReader, 163 | final Class tClass, 164 | final int startIndex) { 165 | return read(csvReader, tClass, startIndex, CsvConst.DEFAULT_END_INDEX); 166 | } 167 | 168 | /** 169 | * 读取文件信息 170 | * 171 | * @param csvReader csv 读取类 172 | * @param tClass 读取类 173 | * @param startIndex 开始下标 174 | * @param endIndex 结束下标 175 | * @param 泛型 176 | * @return 结果列表 177 | * @since 0.0.8 178 | */ 179 | public static List read(final ICsvReader csvReader, 180 | final Class tClass, 181 | final int startIndex, 182 | final int endIndex) { 183 | return CsvReadBs.newInstance() 184 | .reader(csvReader) 185 | .startIndex(startIndex) 186 | .endIndex(endIndex) 187 | .read(tClass); 188 | } 189 | 190 | 191 | /** 192 | * 文件写入 193 | * 1. 默认写入表头 194 | * 2. 什么都不做 195 | * 196 | * @param list 文件列表 197 | * @param 泛型 198 | * @return 结果列表 199 | * @since 0.0.8 200 | */ 201 | public static List write(final List list) { 202 | return write(list, CsvWriters.none()); 203 | } 204 | 205 | /** 206 | * 文件写入 207 | * 1. 默认写入表头 208 | * 209 | * @param list 文件列表 210 | * @param filePath 文件路径 211 | * @param 泛型 212 | * @return 结果列表 213 | * @since 0.0.8 214 | */ 215 | public static List write(final List list, 216 | final String filePath) { 217 | return write(list, filePath, CharsetConst.UTF8); 218 | } 219 | 220 | /** 221 | * 文件写入 222 | * 1. 默认写入表头 223 | * 224 | * @param list 文件列表 225 | * @param filePath 文件路径 226 | * @param charset 文件编码 227 | * @param 泛型 228 | * @return 结果列表 229 | * @since 0.0.8 230 | */ 231 | public static List write(final List list, 232 | final String filePath, 233 | final String charset) { 234 | final ICsvWriter csvWriter = CsvWriters.filePath(filePath, charset); 235 | return write(list, csvWriter); 236 | } 237 | 238 | /** 239 | * 文件写入 240 | * 1. 默认写入表头 241 | * 242 | * @param list 文件列表 243 | * @param csvWriter 写入类实现 244 | * @param 泛型 245 | * @return 结果列表 246 | * @since 0.0.8 247 | */ 248 | public static List write(final List list, 249 | final ICsvWriter csvWriter) { 250 | return write(list, csvWriter, true); 251 | } 252 | 253 | /** 254 | * 文件写入 255 | * 256 | * @param list 文件列表 257 | * @param csvWriter 写入类实现 258 | * @param writeHead 是否写入头信息 259 | * @param 泛型 260 | * @return 结果列表 261 | * @since 0.0.8 262 | */ 263 | public static List write(final List list, 264 | final ICsvWriter csvWriter, 265 | final boolean writeHead) { 266 | return CsvWriteBs.newInstance() 267 | .writer(csvWriter) 268 | .writeHead(writeHead) 269 | .write(list); 270 | } 271 | 272 | } 273 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/util/CsvInnerUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.constant.CsvConst; 4 | import com.github.houbb.csv.constant.CsvEscapeConst; 5 | import com.github.houbb.csv.exception.CsvException; 6 | import com.github.houbb.heaven.constant.PunctuationConst; 7 | import com.github.houbb.heaven.util.lang.CharUtil; 8 | import com.github.houbb.heaven.util.lang.StringUtil; 9 | 10 | import java.util.Collections; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * 内部工具类 16 | * @author binbin.hou 17 | * @since 0.0.5 18 | */ 19 | public final class CsvInnerUtil { 20 | 21 | private CsvInnerUtil(){} 22 | 23 | /** 24 | * 特殊符号与转移字符的映射关系 25 | * @since 0.1.6 26 | */ 27 | private static final Map SPECIAL_ESCAPE_MAP = new HashMap<>(); 28 | 29 | /** 30 | * 特殊符号与转移字符的映射关系 31 | * @since 0.1.6 32 | */ 33 | private static final Map ESCAPE_SPECIAL_MAP = new HashMap<>(); 34 | 35 | static { 36 | SPECIAL_ESCAPE_MAP.put(PunctuationConst.COMMA, CsvEscapeConst.COMMA); 37 | SPECIAL_ESCAPE_MAP.put(CsvConst.SPLIT_OR, CsvEscapeConst.OR); 38 | SPECIAL_ESCAPE_MAP.put(PunctuationConst.COLON, CsvEscapeConst.COLON); 39 | SPECIAL_ESCAPE_MAP.put(PunctuationConst.EQUAL, CsvEscapeConst.EQUAL); 40 | 41 | ESCAPE_SPECIAL_MAP.put(CsvEscapeConst.COMMA, PunctuationConst.COMMA); 42 | ESCAPE_SPECIAL_MAP.put(CsvEscapeConst.OR, CsvConst.SPLIT_OR); 43 | ESCAPE_SPECIAL_MAP.put(CsvEscapeConst.COLON, PunctuationConst.COLON); 44 | ESCAPE_SPECIAL_MAP.put(CsvEscapeConst.EQUAL, PunctuationConst.EQUAL); 45 | } 46 | 47 | /** 48 | * 替换所有特殊字符 49 | * @param special 特殊字符 50 | * @return 替换后的结果 51 | * @since 0.0.6 52 | */ 53 | public static String replaceAllSpecial(final String special) { 54 | if (StringUtil.isEmpty(special)) { 55 | return special; 56 | } 57 | String result = special; 58 | for (Map.Entry entry : SPECIAL_ESCAPE_MAP.entrySet()) { 59 | final String key = entry.getKey(); 60 | final String value = entry.getValue(); 61 | result = result.replaceAll(key, value); 62 | } 63 | return result; 64 | } 65 | 66 | /** 67 | * 替换所有转义字符 68 | * @param escape 转义字符 69 | * @return 替换后的结果 70 | * @since 0.0.6 71 | */ 72 | public static String replaceAllEscape(final String escape) { 73 | if (StringUtil.isEmpty(escape)) { 74 | return escape; 75 | } 76 | String result = escape; 77 | for (Map.Entry entry : ESCAPE_SPECIAL_MAP.entrySet()) { 78 | final String key = entry.getKey(); 79 | final String value = entry.getValue(); 80 | result = result.replaceAll(key, value); 81 | } 82 | return result; 83 | } 84 | 85 | /** 86 | * 获取下一个分隔符号 87 | * @param preSplit 原来的分隔符号 88 | * @return 下一个分隔符 89 | */ 90 | public static String getNextSplit(final String preSplit) { 91 | if(CsvConst.COMMA.equals(preSplit)) { 92 | return CsvConst.ENTRY_SPLIT_UNIT; 93 | } 94 | if(preSplit.startsWith(CsvConst.ENTRY_SPLIT_UNIT)) { 95 | final int times = preSplit.length()+1; 96 | return CharUtil.repeat(CsvConst.ENTRY_SPLIT_UNIT_CHAR, times); 97 | } 98 | throw new UnsupportedOperationException("暂时不支持的分隔符!"); 99 | } 100 | 101 | 102 | /** 103 | * 获取映射 map 104 | * @param mapping 映射信息 105 | * @return map 106 | * @since 0.1.0 107 | */ 108 | public static Map getMappingMap(final String mapping) { 109 | if(StringUtil.isEmpty(mapping)) { 110 | return Collections.emptyMap(); 111 | } 112 | 113 | //; 分割 114 | //: 继续分割 115 | // 这里可以使用 cache 提升性能 116 | String[] entryArray = mapping.split(CsvConst.MAPPING_SPLITTER); 117 | Map map = new HashMap<>(entryArray.length); 118 | for(String entry : entryArray) { 119 | String[] mappings = entry.split(CsvConst.MAPPING_UNIT_SPLITTER); 120 | 121 | if(mappings.length != 2) { 122 | throw new CsvException("枚举映射必须使用单个【:】进行分割。"); 123 | } 124 | 125 | map.put(mappings[0], mappings[1]); 126 | } 127 | 128 | return map; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/csv/util/CsvStringListHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.bs.CsvReadBs; 4 | import com.github.houbb.csv.bs.CsvWriteBs; 5 | import com.github.houbb.csv.constant.CsvConfigConst; 6 | import com.github.houbb.csv.support.reader.impl.CsvReaders; 7 | import com.github.houbb.csv.support.writer.impl.CsvWriters; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * csv 读写工具类 13 | * 14 | * @author binbin.hou 15 | * @since 0.2.0 16 | */ 17 | public final class CsvStringListHelper { 18 | 19 | public static List> read(final String filePath, final int startIx, final int endIx, final char quoteChar) { 20 | return CsvReadBs.newInstance().reader(CsvReaders.filePath(filePath)) 21 | .startIndex(startIx).endIndex(endIx) 22 | .quoteChar(quoteChar).readStringList(); 23 | } 24 | 25 | public static List> read(final String filePath, final int startIx, final int endIx) { 26 | return read(filePath, startIx, endIx, CsvConfigConst.DEFAULT_QUOTE_CHAR); 27 | } 28 | 29 | public static List> read(final String filePath, final int startIx) { 30 | return read(filePath, startIx, Integer.MAX_VALUE); 31 | } 32 | 33 | public static List> read(final String filePath) { 34 | return read(filePath, 0); 35 | } 36 | 37 | public static void write(final String filePath, List> dataList, final char quoteChar) { 38 | CsvWriteBs.newInstance() 39 | .writer(CsvWriters.filePath(filePath)) 40 | .quoteChar(quoteChar) 41 | .writeStringList(dataList); 42 | } 43 | 44 | public static void write(final String filePath, List> dataList) { 45 | write(filePath, dataList, CsvConfigConst.DEFAULT_QUOTE_CHAR); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/csv/b8c10e492545b43ad5f192fd99b2de417bc3ebfa/src/main/resources/readme.txt -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/bs/CsvReadBsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.bs; 2 | 3 | import com.github.houbb.csv.model.*; 4 | import com.github.houbb.csv.support.reader.impl.CsvReaderFilePath; 5 | import com.github.houbb.csv.support.reader.impl.CsvReaders; 6 | import org.junit.Assert; 7 | import org.junit.Ignore; 8 | import org.junit.Test; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @author binbin.hou 14 | * @since 0.0.1 15 | */ 16 | @Ignore 17 | public class CsvReadBsTest { 18 | 19 | @Test 20 | public void commonTest() { 21 | final String path = "src\\test\\resources\\common.csv"; 22 | List userList = CsvReadBs.newInstance() 23 | .reader(CsvReaders.filePath(path)) 24 | .read(User.class); 25 | 26 | final String result = "[User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}]"; 27 | Assert.assertEquals(result, userList.toString()); 28 | } 29 | 30 | /** 31 | * 基于注解 32 | * @since 0.0.2 33 | */ 34 | @Test 35 | public void annotationTest() { 36 | final String path = "src\\test\\resources\\annotation.csv"; 37 | List userList = CsvReadBs.newInstance() 38 | .reader(CsvReaders.filePath(path)) 39 | .read(UserAnnotation.class); 40 | Assert.assertEquals("你好", userList.get(0).name()); 41 | } 42 | 43 | /** 44 | * 集合特性 45 | * @since 0.0.3 46 | */ 47 | @Test 48 | public void collectionTest() { 49 | final String path = "src\\test\\resources\\collection.csv"; 50 | List userList = CsvReadBs.newInstance() 51 | .reader(CsvReaders.filePath(path)) 52 | .read(UserCollection.class); 53 | final String result = "[UserCollection{arrays=[a, b], lists=[a, b, c], maps={key=value, key2=value2}, sets=[set2, set1]}]"; 54 | System.out.println(userList); 55 | } 56 | 57 | /** 58 | * 对象明细特性 59 | * @since 0.0.5 60 | */ 61 | @Test 62 | public void entryTest() { 63 | final String path = "src\\test\\resources\\entry.csv"; 64 | List userList = CsvReadBs.newInstance() 65 | .reader(CsvReaders.filePath(path)) 66 | .read(UserEntry.class); 67 | final String string = "[UserEntry{name='test', user=User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}}]"; 68 | Assert.assertEquals(string, userList.toString()); 69 | } 70 | 71 | /** 72 | * 特殊字符转义 73 | * @since 0.0.6 74 | */ 75 | @Test 76 | public void escapeTest() { 77 | final String path = "src\\test\\resources\\escape.csv"; 78 | List userList = CsvReadBs.newInstance() 79 | .reader(CsvReaders.filePath(path)) 80 | .escape(true) 81 | .read(UserEscape.class); 82 | final String string = "[UserEscape{name='one,one', nameList=[one|one, two|two], user=User{name='entry:name', age=0, score=0.0, money=0.0, sex=false, level=0, id=0, status=, coin=0}, map={key=key=value=value}}]"; 83 | Assert.assertEquals("one,one", userList.get(0).name()); 84 | System.out.println(userList); 85 | } 86 | 87 | /** 88 | * 自引用测试 89 | * @since 0.0.7 90 | */ 91 | @Test 92 | public void selfRefTest() { 93 | final String path = "src\\test\\resources\\selfRef.csv"; 94 | List userList = CsvReadBs.newInstance() 95 | .reader(CsvReaders.filePath(path)) 96 | .read(UserSelfRef.class); 97 | System.out.println(userList); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/bs/CsvWriteBsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.bs; 2 | 3 | import com.github.houbb.csv.model.*; 4 | import com.github.houbb.csv.support.writer.impl.CsvWriters; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.util.*; 9 | 10 | /** 11 | * @author binbin.hou 12 | * @since 0.0.1 13 | */ 14 | @Ignore 15 | public class CsvWriteBsTest { 16 | 17 | @Test 18 | public void commonTest() { 19 | final String path = "src\\test\\resources\\common.csv"; 20 | CsvWriteBs.newInstance() 21 | .writer(CsvWriters.filePath(path)) 22 | .write(buildCommonList()); 23 | } 24 | 25 | /** 26 | * @since 0.0.7 27 | */ 28 | @Test 29 | public void commonWithIdTest() { 30 | final String path = "src\\test\\resources\\common_id.csv"; 31 | 32 | List list = new ArrayList<>(); 33 | UserWithSerialId user = new UserWithSerialId().name("test").age(2020); 34 | list.add(user); 35 | 36 | CsvWriteBs.newInstance() 37 | .writer(CsvWriters.filePath(path)) 38 | .write(list); 39 | } 40 | 41 | /** 42 | * 基于注解的写入测试 43 | * @since 0.0.2 44 | */ 45 | @Test 46 | public void annotationTest() { 47 | final String path = "src\\test\\resources\\annotation.csv"; 48 | CsvWriteBs.newInstance() 49 | .writer(CsvWriters.filePath(path)) 50 | .write(buildAnnotationList()); 51 | } 52 | 53 | /** 54 | * 集合测试 55 | * @since 0.0.3 56 | */ 57 | @Test 58 | public void collectionTest() { 59 | final String path = "src\\test\\resources\\collection.csv"; 60 | CsvWriteBs.newInstance() 61 | .writer(CsvWriters.filePath(path)) 62 | .write(buildCollectionList()); 63 | } 64 | 65 | /** 66 | * 构建明细信息测试 67 | * @since 0.0.5 68 | */ 69 | @Test 70 | public void entryTest() { 71 | final String path = "src\\test\\resources\\entry.csv"; 72 | CsvWriteBs.newInstance() 73 | .writer(CsvWriters.filePath(path)) 74 | .write(buildEntryList()); 75 | } 76 | 77 | /** 78 | * 构建特殊信息转义信息测试 79 | * @since 0.0.6 80 | */ 81 | @Test 82 | public void escapeTest() { 83 | final String path = "src\\test\\resources\\escape.csv"; 84 | CsvWriteBs.newInstance() 85 | .writer(CsvWriters.filePath(path)) 86 | .escape(true) 87 | .write(buildUserEscapeList()); 88 | } 89 | 90 | /** 91 | * 自引用测试 92 | * @since 0.0.7 93 | */ 94 | @Test 95 | public void selfRefTest() { 96 | final String path = "src\\test\\resources\\selfRef.csv"; 97 | CsvWriteBs.newInstance() 98 | .writer(CsvWriters.filePath(path)) 99 | .write(buildUserSelfRefs()); 100 | } 101 | 102 | /** 103 | * 构建自引用列表 104 | * @return 列表 105 | * @since 0.0.7 106 | */ 107 | private List buildUserSelfRefs() { 108 | UserSelfRef userSelfRef = new UserSelfRef(); 109 | UserSelfRef child = new UserSelfRef(); 110 | child.name("child"); 111 | 112 | userSelfRef.name("123"); 113 | userSelfRef.selfRef(child); 114 | return Collections.singletonList(userSelfRef); 115 | } 116 | 117 | /** 118 | * 构建待转换的结果表 119 | * @return 结果列表 120 | * @since 0.0.6 121 | */ 122 | private List buildUserEscapeList() { 123 | UserEscape escape = new UserEscape(); 124 | Map map = new HashMap<>(); 125 | map.put("key=key", "value=value"); 126 | User user = new User(); 127 | user.name("entry:name"); 128 | 129 | escape.name("one,one"); 130 | escape.nameList(Arrays.asList("one|one", "two|two")); 131 | escape.map(map); 132 | escape.user(user); 133 | 134 | return Collections.singletonList(escape); 135 | } 136 | 137 | /** 138 | * 构建通用测试列表 139 | * @return 列表 140 | */ 141 | private List buildCommonList() { 142 | User user = new User(); 143 | short s = 4; 144 | byte b = 1; 145 | user.age(10) 146 | .name("你好") 147 | .id(1L) 148 | .score(60) 149 | .coin(b) 150 | .level(s) 151 | .money(200) 152 | .sex(true) 153 | .status('Y'); 154 | return Arrays.asList(user); 155 | } 156 | 157 | /** 158 | * 构建基于注解的测试列表 159 | * @return 列表 160 | */ 161 | private List buildAnnotationList() { 162 | UserAnnotation user = new UserAnnotation(); 163 | user.name("你好") 164 | .password("123") 165 | .birthday(new Date()); 166 | return Arrays.asList(user); 167 | } 168 | 169 | /** 170 | * 构建基于集合的测试列表 171 | * @return 列表 172 | * @since 0.0.3 173 | */ 174 | private List buildCollectionList() { 175 | UserCollection user = new UserCollection(); 176 | String[] arrays = new String[]{"a", "b", "c"}; 177 | LinkedList lists = new LinkedList<>(Arrays.asList(arrays)); 178 | Map maps = new HashMap<>(); 179 | maps.put("key", "value"); 180 | maps.put("key2", "value2"); 181 | Set sets = new HashSet<>(); 182 | sets.add("set1"); 183 | sets.add("set2"); 184 | 185 | user.setLists(lists); 186 | user.setArrays(arrays); 187 | user.setMaps(maps); 188 | user.setSets(sets); 189 | return Arrays.asList(user); 190 | } 191 | 192 | /** 193 | * 用户明细列表 194 | * @return 明细列表 195 | * @since 0.0.5 196 | */ 197 | private List buildEntryList() { 198 | UserEntry userEntry = new UserEntry(); 199 | userEntry.name("test"); 200 | userEntry.user(buildCommonList().get(0)); 201 | return Collections.singletonList(userEntry); 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/bs/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.bs; -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/convert/ReadDateConvert.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.convert; 2 | 3 | import com.github.houbb.csv.api.IReadConverter; 4 | import com.github.houbb.csv.support.context.SingleReadContext; 5 | 6 | import java.text.DateFormat; 7 | import java.text.ParseException; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | 11 | /** 12 | * 读取时 13 | * @author binbin.hou 14 | * @since 0.0.2 15 | */ 16 | public class ReadDateConvert implements IReadConverter { 17 | 18 | @Override 19 | public Date convert(SingleReadContext context) { 20 | try { 21 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); 22 | return dateFormat.parse(context.value()); 23 | } catch (ParseException e) { 24 | throw new RuntimeException(e); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/convert/WriteDateConvert.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.convert; 2 | 3 | import com.github.houbb.csv.api.IWriteConverter; 4 | import com.github.houbb.csv.support.context.SingleWriteContext; 5 | 6 | import java.text.DateFormat; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | /** 11 | * 写入时 12 | * @author binbin.hou 13 | * @since 0.0.2 14 | */ 15 | public class WriteDateConvert implements IWriteConverter { 16 | 17 | @Override 18 | public String convert(SingleWriteContext context) { 19 | final Date value = (Date)context.value(); 20 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); 21 | return dateFormat.format(value); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/convert/WriteStatusEnumConvert.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.convert; 2 | 3 | import com.github.houbb.csv.enums.StatusEnum; 4 | import com.github.houbb.csv.support.convert.read.AbstractCodeDescWriteConverter; 5 | 6 | /** 7 | * @author binbin.hou 8 | * @since 0.1.0 9 | */ 10 | public class WriteStatusEnumConvert extends AbstractCodeDescWriteConverter { 11 | 12 | @Override 13 | protected StatusEnum[] codeDescArray() { 14 | return StatusEnum.values(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/enums/StatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.enums; 2 | 3 | import com.github.houbb.csv.api.ICodeDesc; 4 | 5 | /** 6 | * @author binbin.hou 7 | * @since 0.1.0 8 | */ 9 | public enum StatusEnum implements ICodeDesc { 10 | 11 | SUCCESS("ok", "成功"), 12 | FAIL("fail", "失败"), 13 | ; 14 | 15 | private final String code; 16 | private final String desc; 17 | 18 | StatusEnum(String code, String desc) { 19 | this.code = code; 20 | this.desc = desc; 21 | } 22 | 23 | @Override 24 | public String getCode() { 25 | return code; 26 | } 27 | 28 | @Override 29 | public String getDesc() { 30 | return desc; 31 | } 32 | 33 | @Override 34 | public ICodeDesc[] list() { 35 | return StatusEnum.values(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/User.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | /** 4 | * @author binbin.hou 5 | * @since 0.0.1 6 | */ 7 | public class User { 8 | 9 | private String name; 10 | 11 | private int age; 12 | 13 | private float score; 14 | 15 | private double money; 16 | 17 | private boolean sex; 18 | 19 | private short level; 20 | 21 | private long id; 22 | 23 | private char status; 24 | 25 | private byte coin; 26 | 27 | public String name() { 28 | return name; 29 | } 30 | 31 | public User name(String name) { 32 | this.name = name; 33 | return this; 34 | } 35 | 36 | public int age() { 37 | return age; 38 | } 39 | 40 | public User age(int age) { 41 | this.age = age; 42 | return this; 43 | } 44 | 45 | public float score() { 46 | return score; 47 | } 48 | 49 | public User score(float score) { 50 | this.score = score; 51 | return this; 52 | } 53 | 54 | public double money() { 55 | return money; 56 | } 57 | 58 | public User money(double money) { 59 | this.money = money; 60 | return this; 61 | } 62 | 63 | public boolean sex() { 64 | return sex; 65 | } 66 | 67 | public User sex(boolean sex) { 68 | this.sex = sex; 69 | return this; 70 | } 71 | 72 | public short level() { 73 | return level; 74 | } 75 | 76 | public User level(short level) { 77 | this.level = level; 78 | return this; 79 | } 80 | 81 | public long id() { 82 | return id; 83 | } 84 | 85 | public User id(long id) { 86 | this.id = id; 87 | return this; 88 | } 89 | 90 | public char status() { 91 | return status; 92 | } 93 | 94 | public User status(char status) { 95 | this.status = status; 96 | return this; 97 | } 98 | 99 | public byte coin() { 100 | return coin; 101 | } 102 | 103 | public User coin(byte coin) { 104 | this.coin = coin; 105 | return this; 106 | } 107 | 108 | @Override 109 | public String toString() { 110 | return "User{" + 111 | "name='" + name + '\'' + 112 | ", age=" + age + 113 | ", score=" + score + 114 | ", money=" + money + 115 | ", sex=" + sex + 116 | ", level=" + level + 117 | ", id=" + id + 118 | ", status=" + status + 119 | ", coin=" + coin + 120 | '}'; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | import com.github.houbb.csv.convert.ReadDateConvert; 5 | import com.github.houbb.csv.convert.WriteDateConvert; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * 基于注解的测试案例 11 | * @author binbin.hou 12 | * @since 0.0.2 13 | */ 14 | public class UserAnnotation { 15 | 16 | @Csv(label = "名称") 17 | private String name; 18 | 19 | @Csv(label = "密码", readRequire = false, writeRequire = false) 20 | private String password; 21 | 22 | @Csv(label = "生日", readConverter = ReadDateConvert.class, writeConverter = WriteDateConvert.class) 23 | private Date birthday; 24 | 25 | public String name() { 26 | return name; 27 | } 28 | 29 | public UserAnnotation name(String name) { 30 | this.name = name; 31 | return this; 32 | } 33 | 34 | public String password() { 35 | return password; 36 | } 37 | 38 | public UserAnnotation password(String password) { 39 | this.password = password; 40 | return this; 41 | } 42 | 43 | public Date birthday() { 44 | return birthday; 45 | } 46 | 47 | public UserAnnotation birthday(Date birthday) { 48 | this.birthday = birthday; 49 | return this; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "UserAnnotation{" + 55 | "name='" + name + '\'' + 56 | ", password='" + password + '\'' + 57 | ", birthday=" + birthday + 58 | '}'; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserCollection.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * 支持集合 7 | * (1)array 8 | * (2)list/set 9 | * (3)map 10 | * @author binbin.hou 11 | * @since 0.0.3 12 | */ 13 | public class UserCollection { 14 | 15 | private String[] arrays; 16 | 17 | private LinkedList lists; 18 | 19 | private Map maps; 20 | 21 | private Set sets; 22 | 23 | public String[] getArrays() { 24 | return arrays; 25 | } 26 | 27 | public void setArrays(String[] arrays) { 28 | this.arrays = arrays; 29 | } 30 | 31 | public LinkedList getLists() { 32 | return lists; 33 | } 34 | 35 | public void setLists(LinkedList lists) { 36 | this.lists = lists; 37 | } 38 | 39 | public Map getMaps() { 40 | return maps; 41 | } 42 | 43 | public void setMaps(Map maps) { 44 | this.maps = maps; 45 | } 46 | 47 | public Set getSets() { 48 | return sets; 49 | } 50 | 51 | public void setSets(Set sets) { 52 | this.sets = sets; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "UserCollection{" + 58 | "arrays=" + Arrays.toString(arrays) + 59 | ", lists=" + lists + 60 | ", maps=" + maps + 61 | ", sets=" + sets + 62 | '}'; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserEntry.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import com.github.houbb.csv.annotation.CsvEntry; 4 | 5 | /** 6 | * 用户明细测试 7 | * @author binbin.hou 8 | * @since 0.0.5 9 | */ 10 | public class UserEntry { 11 | 12 | /** 13 | * 名称 14 | */ 15 | private String name; 16 | 17 | /** 18 | * 内嵌的用户信息 19 | */ 20 | @CsvEntry 21 | private User user; 22 | 23 | public String name() { 24 | return name; 25 | } 26 | 27 | public UserEntry name(String name) { 28 | this.name = name; 29 | return this; 30 | } 31 | 32 | public User user() { 33 | return user; 34 | } 35 | 36 | public UserEntry user(User user) { 37 | this.user = user; 38 | return this; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "UserEntry{" + 44 | "name='" + name + '\'' + 45 | ", user=" + user + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserEscape.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import com.github.houbb.csv.annotation.CsvEntry; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * 特殊字符转义处理 10 | * @author binbin.hou 11 | * @since 0.0.6 12 | */ 13 | public class UserEscape { 14 | 15 | /** 16 | * 使用 , 17 | */ 18 | private String name; 19 | 20 | /** 21 | * 使用 map = 22 | */ 23 | private Map map; 24 | 25 | /** 26 | * 使用 | 27 | */ 28 | private List nameList; 29 | 30 | /** 31 | * 使用 : 32 | */ 33 | @CsvEntry 34 | private User user; 35 | 36 | public String name() { 37 | return name; 38 | } 39 | 40 | public UserEscape name(String name) { 41 | this.name = name; 42 | return this; 43 | } 44 | 45 | public List nameList() { 46 | return nameList; 47 | } 48 | 49 | public UserEscape nameList(List nameList) { 50 | this.nameList = nameList; 51 | return this; 52 | } 53 | 54 | public User user() { 55 | return user; 56 | } 57 | 58 | public UserEscape user(User user) { 59 | this.user = user; 60 | return this; 61 | } 62 | 63 | public Map map() { 64 | return map; 65 | } 66 | 67 | public UserEscape map(Map map) { 68 | this.map = map; 69 | return this; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "UserEscape{" + 75 | "name='" + name + '\'' + 76 | ", nameList=" + nameList + 77 | ", user=" + user + 78 | ", map=" + map + 79 | '}'; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserMapping.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import com.github.houbb.csv.annotation.Csv; 4 | 5 | /** 6 | * @author binbin.hou 7 | * @since 0.1.0 8 | */ 9 | public class UserMapping { 10 | 11 | @Csv(readMapping = "S:成功;F:失败", writeMapping = "S:成功;F:失败") 12 | private String status; 13 | 14 | public String status() { 15 | return status; 16 | } 17 | 18 | public UserMapping status(String status) { 19 | this.status = status; 20 | return this; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "UserMapping{" + 26 | "status='" + status + '\'' + 27 | '}'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserSelfRef.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import com.github.houbb.csv.annotation.CsvEntry; 4 | 5 | /** 6 | * 用户自引用 7 | * 测试目的:自己引用自己,是否会出问题。 8 | * @author binbin.hou 9 | * @since 0.0.7 10 | */ 11 | public class UserSelfRef { 12 | 13 | private String name; 14 | 15 | @CsvEntry 16 | private UserSelfRef selfRef; 17 | 18 | public String name() { 19 | return name; 20 | } 21 | 22 | public UserSelfRef name(String name) { 23 | this.name = name; 24 | return this; 25 | } 26 | 27 | public UserSelfRef selfRef() { 28 | return selfRef; 29 | } 30 | 31 | public UserSelfRef selfRef(UserSelfRef selfRef) { 32 | this.selfRef = selfRef; 33 | return this; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "UserSelfRef{" + 39 | "name='" + name + '\'' + 40 | ", selfRef=" + selfRef + 41 | '}'; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserType.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import com.github.houbb.heaven.util.lang.reflect.ClassUtil; 4 | import com.github.houbb.heaven.util.lang.reflect.ReflectFieldUtil; 5 | 6 | import java.lang.reflect.Field; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author binbin.hou 12 | * @since 1.0.0 13 | */ 14 | public class UserType { 15 | 16 | private Map stringMap; 17 | 18 | private Map wildcardMap; 19 | 20 | private Map objectMap; 21 | 22 | /** 23 | * String 的父类 24 | */ 25 | private List wildcardSuperList; 26 | 27 | /** 28 | * String 的子类 29 | */ 30 | private List wildcardExtendsList; 31 | 32 | private List wildcardList; 33 | 34 | private String[] strings; 35 | 36 | private Object[] objects; 37 | 38 | private List stringList; 39 | 40 | private List objectList; 41 | 42 | public String[] getStrings() { 43 | return strings; 44 | } 45 | 46 | public void setStrings(String[] strings) { 47 | this.strings = strings; 48 | } 49 | 50 | public Object[] getObjects() { 51 | return objects; 52 | } 53 | 54 | public void setObjects(Object[] objects) { 55 | this.objects = objects; 56 | } 57 | 58 | public List getStringList() { 59 | return stringList; 60 | } 61 | 62 | public void setStringList(List stringList) { 63 | this.stringList = stringList; 64 | } 65 | 66 | public List getObjectList() { 67 | return objectList; 68 | } 69 | 70 | public void setObjectList(List objectList) { 71 | this.objectList = objectList; 72 | } 73 | 74 | public List getWildcardList() { 75 | return wildcardList; 76 | } 77 | 78 | public void setWildcardList(List wildcardList) { 79 | this.wildcardList = wildcardList; 80 | } 81 | 82 | public List getWildcardSuperList() { 83 | return wildcardSuperList; 84 | } 85 | 86 | public void setWildcardSuperList(List wildcardSuperList) { 87 | this.wildcardSuperList = wildcardSuperList; 88 | } 89 | 90 | public List getWildcardExtendsList() { 91 | return wildcardExtendsList; 92 | } 93 | 94 | public void setWildcardExtendsList(List wildcardExtendsList) { 95 | this.wildcardExtendsList = wildcardExtendsList; 96 | } 97 | 98 | public Map getStringMap() { 99 | return stringMap; 100 | } 101 | 102 | public void setStringMap(Map stringMap) { 103 | this.stringMap = stringMap; 104 | } 105 | 106 | public Map getWildcardMap() { 107 | return wildcardMap; 108 | } 109 | 110 | public void setWildcardMap(Map wildcardMap) { 111 | this.wildcardMap = wildcardMap; 112 | } 113 | 114 | public Map getObjectMap() { 115 | return objectMap; 116 | } 117 | 118 | public void setObjectMap(Map objectMap) { 119 | this.objectMap = objectMap; 120 | } 121 | 122 | public static void main(String[] args) { 123 | List fieldList = ClassUtil.getAllFieldList(UserType.class); 124 | for(Field field : fieldList) { 125 | System.out.println(ReflectFieldUtil.getComponentType(field)); 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/model/UserWithSerialId.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | *

project: csv-UserWithSerialId

7 | *

create on 2020/2/10 9:07

8 | * 9 | * @author Administrator 10 | * @since 0.0.1 11 | */ 12 | public class UserWithSerialId implements Serializable { 13 | 14 | private static final long serialVersionUID = -6243135423619414366L; 15 | 16 | private String name; 17 | 18 | private int age; 19 | 20 | public String name() { 21 | return name; 22 | } 23 | 24 | public UserWithSerialId name(String name) { 25 | this.name = name; 26 | return this; 27 | } 28 | 29 | public int age() { 30 | return age; 31 | } 32 | 33 | public UserWithSerialId age(int age) { 34 | this.age = age; 35 | return this; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "UserWithSerialId{" + 41 | "name='" + name + '\'' + 42 | ", age=" + age + 43 | '}'; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/util/CsvHelperReaderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.model.User; 4 | import com.github.houbb.csv.model.UserMapping; 5 | import org.junit.Assert; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | /** 13 | * @author binbin.hou 14 | * @since 0.0.8 15 | */ 16 | @Ignore 17 | public class CsvHelperReaderTest { 18 | 19 | /** 20 | * 读取列表 21 | * @since 0.0.8 22 | */ 23 | @Test 24 | public void readListTest() { 25 | List lines = Arrays.asList("name,age,score,money,sex,level,id,status,coin", 26 | "你好,10,60.0,200.0,true,4,1,Y,1"); 27 | 28 | List userList = CsvHelper.read(lines, User.class); 29 | Assert.assertEquals("[User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}]", userList.toString()); 30 | } 31 | 32 | /** 33 | * 读取列表 34 | * @since 0.0.8 35 | */ 36 | @Test 37 | public void readFilePathTest() { 38 | final String path = "src\\test\\resources\\common.csv"; 39 | 40 | List userList = CsvHelper.read(path, User.class); 41 | Assert.assertEquals("[User{name='你好', age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}]", userList.toString()); 42 | } 43 | 44 | /** 45 | * 映射列表 46 | * @since 0.1.0 47 | */ 48 | @Test 49 | public void readMappingTest() { 50 | final String path = "src\\test\\resources\\mapping.csv"; 51 | 52 | List userList = CsvHelper.read(path, UserMapping.class); 53 | Assert.assertEquals("[UserMapping{status='S'}]", userList.toString()); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/util/CsvHelperWriterTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.model.User; 4 | import com.github.houbb.csv.model.UserMapping; 5 | import com.github.houbb.csv.support.reader.impl.CsvReaders; 6 | import com.github.houbb.csv.support.writer.impl.CsvWriters; 7 | import org.junit.Assert; 8 | import org.junit.Ignore; 9 | import org.junit.Test; 10 | 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | /** 16 | * @author binbin.hou 17 | * @since 0.0.8 18 | */ 19 | @Ignore 20 | public class CsvHelperWriterTest { 21 | 22 | /** 23 | * 读取列表 24 | * @since 0.0.8 25 | */ 26 | @Test 27 | public void writerTest() { 28 | List userList = buildCommonList(); 29 | 30 | CsvHelper.write(userList); 31 | CsvHelper.write(userList, CsvWriters.console()); 32 | } 33 | 34 | @Test 35 | public void writerFileTest() { 36 | final String path = "src\\test\\resources\\helper.csv"; 37 | 38 | CsvHelper.write(buildCommonList(), CsvWriters.filePath(path)); 39 | } 40 | 41 | /** 42 | * @since 0.1.0 43 | */ 44 | @Test 45 | public void writeMappingTest() { 46 | UserMapping userMapping = new UserMapping(); 47 | userMapping.status("S"); 48 | 49 | CsvHelper.write(Collections.singletonList(userMapping), CsvWriters.filePath("src\\test\\resources\\mapping.csv")); 50 | } 51 | 52 | /** 53 | * 构建通用测试列表 54 | * @return 列表 55 | */ 56 | private List buildCommonList() { 57 | User user = new User(); 58 | short s = 4; 59 | byte b = 1; 60 | user.age(10) 61 | .name("你好") 62 | .id(1L) 63 | .score(60) 64 | .coin(b) 65 | .level(s) 66 | .money(200) 67 | .sex(true) 68 | .status('Y'); 69 | return Arrays.asList(user); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/util/CsvStringListHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import com.github.houbb.csv.model.User; 4 | import com.github.houbb.csv.model.UserMapping; 5 | import com.github.houbb.csv.support.writer.impl.CsvWriters; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * @author binbin.hou 15 | * @since 0.0.8 16 | */ 17 | @Ignore 18 | public class CsvStringListHelperTest { 19 | 20 | /** 21 | * 读取列表 22 | * @since 0.0.8 23 | */ 24 | @Test 25 | public void readTest() { 26 | final String path = "D:\\code\\github\\csv\\src\\test\\resources\\stringlist.csv"; 27 | final String target = "D:\\code\\github\\csv\\src\\test\\resources\\stringlist2.csv"; 28 | 29 | List> dataList = CsvStringListHelper.read(path); 30 | System.out.println(dataList); 31 | 32 | CsvStringListHelper.write(target, dataList); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/csv/util/SplitTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.csv.util; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | 8 | /** 9 | * @author binbin.hou 10 | * @since 0.0.1 11 | */ 12 | @Ignore 13 | public class SplitTest { 14 | 15 | @Test 16 | public void splitTest() { 17 | final String original = "1:2:3:4"; 18 | System.out.println(Arrays.toString(original.split(":"))); 19 | } 20 | 21 | @Test 22 | public void split2Test() { 23 | final String original = "2:3:31::32:4:5"; 24 | System.out.println(Arrays.toString(original.split(":"))); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/resources/annotation.csv: -------------------------------------------------------------------------------- 1 | 名称,生日 2 | 你好,20190620 3 | 你好,20191203 4 | 你好,20200210 5 | -------------------------------------------------------------------------------- /src/test/resources/collection.csv: -------------------------------------------------------------------------------- 1 | arrays,lists,maps,sets 2 | a|b|c,a|b|c,key2=value2|key=value,set1|set2 3 | -------------------------------------------------------------------------------- /src/test/resources/common.csv: -------------------------------------------------------------------------------- 1 | name,age,score,money,sex,level,id,status,coin 2 | 你好,10,60.0,200.0,true,4,1,Y,1 3 | -------------------------------------------------------------------------------- /src/test/resources/common_id.csv: -------------------------------------------------------------------------------- 1 | name,age 2 | test,2020 3 | -------------------------------------------------------------------------------- /src/test/resources/entry.csv: -------------------------------------------------------------------------------- 1 | name,user 2 | test,你好:10:60.0:200.0:true:4:1:Y:1 3 | -------------------------------------------------------------------------------- /src/test/resources/escape.csv: -------------------------------------------------------------------------------- 1 | name,map,nameList,user 2 | one&CSV_COMMA;one,key&CSV_EUQAL;key=value&CSV_EUQAL;value,one&CSV_OR;one|two&CSV_OR;two,entry&CSV_COLON;name:0:0.0:0.0:false:0:0::0 3 | -------------------------------------------------------------------------------- /src/test/resources/helper.csv: -------------------------------------------------------------------------------- 1 | name,age,score,money,sex,level,id,status,coin 2 | 你好,10,60.0,200.0,true,4,1,Y,1 3 | -------------------------------------------------------------------------------- /src/test/resources/mapping.csv: -------------------------------------------------------------------------------- 1 | status 2 | 成功 3 | -------------------------------------------------------------------------------- /src/test/resources/selfRef.csv: -------------------------------------------------------------------------------- 1 | name,selfRef 2 | 123,child: 3 | -------------------------------------------------------------------------------- /src/test/resources/stringlist.csv: -------------------------------------------------------------------------------- 1 | id,name,age 2 | 1,"user,1",10 3 | 2,"user,1",201 -------------------------------------------------------------------------------- /src/test/resources/stringlist2.csv: -------------------------------------------------------------------------------- 1 | id,name,age 2 | 1,"user,1",10 3 | 2,"user,1",201 4 | --------------------------------------------------------------------------------