摘要:創(chuàng)作原由以前覺得文件的讀寫非常簡(jiǎn)單,就懶得封裝。為了解決上述問題,此框架應(yīng)運(yùn)而生。寫入文件其中列表構(gòu)建構(gòu)建基于注解的測(cè)試列表列表你好生成文件內(nèi)容名稱生日你好讀取文件測(cè)試日志信息你好集合類有時(shí)候?qū)ο笾袝?huì)包含數(shù)組等常見集合。
CSV
基于 java 注解的 csv 讀寫框架。
相關(guān)框架Apache commons-csv
super-csv
簡(jiǎn)單看了下,這兩個(gè)框架提供的特性都非常的基礎(chǔ)。
創(chuàng)作原由以前覺得 csv 文件的讀寫非常簡(jiǎn)單,就懶得封裝。
最近一個(gè)月寫了兩次 csv 文件相關(guān)的東西,發(fā)現(xiàn)要處理的細(xì)節(jié)還是有的,還浪費(fèi)比較多的時(shí)間。
比如:
UTF-8 中文編碼使用 excel 打開亂碼,因?yàn)槿鄙?BOM 頭。
不同類型字段轉(zhuǎn)化為字符串,順序的指定,head 頭的指定,如果手寫都會(huì)很繁瑣。
讀取的時(shí)候最后 , 后無(wú)元素,split 會(huì)缺失等。
為了解決上述問題,此框架應(yīng)運(yùn)而生。
特性Fluent 流式寫法
基于 java 注解,支持自定義的轉(zhuǎn)換和靈活配置
內(nèi)置 8 大基本類型以及 String 類型轉(zhuǎn)換
解決 Excel 直接打開,utf-8 亂碼問題
支持集合、數(shù)組、Map 的存取
支持對(duì)象中內(nèi)嵌其他對(duì)象
支持特殊字符轉(zhuǎn)義
變更日志CHANGE_LOG.md
開源地址csv
快速開始 環(huán)境jdk7+
maven 3.x
maven 引入示例代碼com.github.houbb csv 0.0.6
User.java
演示基本類型的轉(zhuǎn)換
public class User { private String name; private int age; private float score; private double money; private boolean sex; private short level; private long id; private char status; private byte coin; //Getter & Setter & toString() }
對(duì)象列表構(gòu)建
/** * 構(gòu)建通用測(cè)試列表 * @return 列表 */ private List寫入buildCommonList() { User user = new User(); short s = 4; byte b = 1; user.age(10) .name("你好") .id(1L) .score(60) .coin(b) .level(s) .money(200) .sex(true) .status("Y"); return Arrays.asList(user); }
測(cè)試代碼
public void commonTest() { final String path = "src est esourcescommon.csv"; CsvWriteBs.newInstance(path) .write(buildCommonList()); }
文件生成
name,age,score,money,sex,level,id,status,coin 你好,10,60.0,200.0,true,4,1,Y,1讀取
public void commonTest() { final String path = "src est esourcescommon.csv"; ListuserList = CsvReadBs.newInstance(path) .read(User.class); System.out.println(userList); }
日志信息
[User{name="你好", age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}]引導(dǎo)類 為什么需要引導(dǎo)類
為了靈活的配置和默認(rèn)配置并存,使用工具類會(huì)大大降低靈活性。
為了用戶使用的便利性,和后期拓展的靈活性。
引導(dǎo)類CSV 有兩個(gè)引導(dǎo)類:
名稱 | 作用 |
---|---|
CsvWriteBs | csv 文件寫入引導(dǎo)類 |
CsvReadBs | csv 文件讀取引導(dǎo)類 |
方法 | 默認(rèn)值 | 說(shuō)明 |
---|---|---|
newInstance(final String path) | 必填 | 創(chuàng)建實(shí)例,并且指定待寫入文件路徑。 |
path (final String path) | 配置文件路徑,只有重新指定 path 路徑時(shí)需要調(diào)用。 | |
writeHead(boolean writeBom) | true | 是否寫入 head 頭,如果想指定名稱,可以結(jié)合注解。只有無(wú) head 信息時(shí),會(huì)寫入。 |
writeBom(boolean writeBom) | true | 是否寫入 UTF8 BOM 頭,只有文件為空時(shí)才會(huì)寫入。 |
charset(String charset) | UTF-8 | 指定文件編碼 |
sort(ISort sort) | NoSort | 默認(rèn)不進(jìn)行字段排序 |
write(List |
無(wú) | 待寫入的文件列表 |
escape | false | 是否進(jìn)行特殊字符的轉(zhuǎn)換 |
方法 | 默認(rèn)值 | 說(shuō)明 |
---|---|---|
newInstance(final String path) | 必填 | 創(chuàng)建實(shí)例,并且指定待讀取文件路徑。 |
path (final String path) | 配置文件路徑,只有重新指定 path 路徑時(shí)需要調(diào)用。 | |
charset(String charset) | UTF-8 | 指定文件編碼 |
sort(ISort sort) | NoSort | 默認(rèn)不進(jìn)行字段排序 |
startIndex(int startIndex) | 1 | 文件的第二行,默認(rèn)第一行是 head |
endIndex(int endIndex) | 文件的最后一行 | |
escape | false | 是否進(jìn)行特殊字符的轉(zhuǎn)換 |
用于待處理對(duì)象的字段上。
/** * 字段顯示名稱 * 1. 默認(rèn)使用 field.name * @return 顯示名稱 */ String label() default ""; /** * 讀取是否需要 * @return 是 */ boolean readRequire() default true; /** * 寫入是否需要 * @return 是 */ boolean writeRequire() default true; /** * 讀取轉(zhuǎn)換 * @return 處理實(shí)現(xiàn)類 */ Class extends IReadConverter> readConverter() default CommonReadConverter.class; /** * 寫入轉(zhuǎn)換 * @return 處理實(shí)現(xiàn)類 */ Class extends IWriteConverter> writeConverter() default StringWriteConverter.class;屬性概覽表
屬性 | 默認(rèn)值 | 說(shuō)明 |
---|---|---|
label | 字段名稱 | 用于 csv 頭生成 |
readRequire | true | 是否需要從 csv 文件讀取 |
writeRequire | true | 當(dāng)前字段是否需要寫入 csv 文件 |
readConverter | CommonReadConverter | 將 csv 中的字符串轉(zhuǎn)化為當(dāng)前字段類型,支持 8 大基本類型+String |
writeConverter | StringWriteConverter | 直接調(diào)用當(dāng)前字段值 toString() 方法,null 直接為空字符串 |
其中 readConverter/writeConverter 支持用戶自定義
字段注解 對(duì)象定義public class UserAnnotation { @Csv(label = "名稱") private String name; @Csv(label = "密碼", readRequire = false, writeRequire = false) private String password; @Csv(label = "生日", readConverter = ReadDateConvert.class, writeConverter = WriteDateConvert.class) private Date birthday; //Getter & Setter & toString() }ReadDateConvert/WriteDateConvert
使我們自定義的針對(duì) Date 的轉(zhuǎn)換實(shí)現(xiàn)。
Write
public class WriteDateConvert implements IWriteConverter{ @Override public String convert(Date value) { DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); return dateFormat.format(value); } }
ReadDateConvert
public class ReadDateConvert implements IReadConverter寫入文件{ @Override public Date convert(String value, Class fieldType) { try { DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); return dateFormat.parse(value); } catch (ParseException e) { throw new RuntimeException(e); } } }
public void annotationTest() { final String path = "src est esourcesannotation.csv"; CsvWriteBs.newInstance(path) .write(buildAnnotationList()); }
其中列表構(gòu)建:
/** * 構(gòu)建基于注解的測(cè)試列表 * @return 列表 */ private ListbuildAnnotationList() { UserAnnotation user = new UserAnnotation(); user.name("你好") .password("123") .birthday(new Date()); return Arrays.asList(user); }
生成文件內(nèi)容
名稱,生日 你好,20190603讀取文件測(cè)試
public void annotationTest() { final String path = "src est esourcesannotation.csv"; ListuserList = CsvReadBs.newInstance(path) .read(UserAnnotation.class); System.out.println(userList); }
日志信息
[UserAnnotation{name="你好", password="null", birthday=Mon Jun 03 00:00:00 CST 2019}]集合類
有時(shí)候?qū)ο笾袝?huì)包含數(shù)組、Map、Collection 等常見集合。
為了存儲(chǔ)的便利性,默認(rèn)提供集合的相關(guān)支持。
特性和普通字段保持一致,如果指定注解轉(zhuǎn)換,則以注解為準(zhǔn)。
使用示例UserCollection.java
用于演示集合的對(duì)象
public class UserCollection { private String[] arrays; private LinkedList存儲(chǔ)lists; private Map maps; private Set sets; //Getter/Setter/toString() }
待存儲(chǔ)對(duì)象的構(gòu)建
/** * 構(gòu)建基于集合的測(cè)試列表 * @return 列表 * @since 0.0.3 */ private ListbuildCollectionList() { UserCollection user = new UserCollection(); String[] arrays = new String[]{"a", "b", "c"}; LinkedList lists = new LinkedList<>(Arrays.asList(arrays)); Map maps = new HashMap<>(); maps.put("key", "value"); maps.put("key2", "value2"); Set sets = new HashSet<>(); sets.add("set1"); sets.add("set2"); user.setLists(lists); user.setArrays(arrays); user.setMaps(maps); user.setSets(sets); return Arrays.asList(user); }
執(zhí)行存儲(chǔ)
public void collectionTest() { final String path = "src est esourcescollection.csv"; CsvWriteBs.newInstance(path) .write(buildCollectionList()); }
存儲(chǔ)效果
?arrays,lists,maps,sets a|b,a|b|c,key2=value2|key=value,set1|set2讀取
測(cè)試類
public void collectionTest() { final String path = "src est esourcescollection.csv"; ListuserList = CsvReadBs.newInstance(path) .read(UserCollection.class); System.out.println(userList); }
測(cè)試日志
[UserCollection{arrays=[a, b], lists=[a, b, c], maps={key=value, key2=value2}, sets=[set2, set1]}]注意
為了保證 csv 以 , 分隔的統(tǒng)一性。
集合使用 | 進(jìn)行分隔,其中 map 的 key/value 分隔,用到了 =。
在使用時(shí)要注意,不要包含上述的符號(hào),否則會(huì)出現(xiàn)解析錯(cuò)亂。
ps: 如果確實(shí)用到這些字符,可以見后面的特殊字符轉(zhuǎn)義功能。
支持內(nèi)嵌對(duì)象有時(shí)候我們希望像使用 mongoDB 一樣,非常方便的存取 csv 的嵌套對(duì)象。
對(duì)于普通的 csv 都沒有實(shí)現(xiàn)這個(gè)特性,本次做了一個(gè)嘗試,支持內(nèi)嵌對(duì)象的存取。
取舍就像 csv 的簡(jiǎn)單,需要用到符號(hào) , 一樣。
內(nèi)嵌對(duì)象為了不破壞 csv 的規(guī)范,使用了符號(hào) :。
換言之,也就是對(duì)象內(nèi)容中不能使用這個(gè)符號(hào)。
后期會(huì)針對(duì)出現(xiàn)的符號(hào)進(jìn)行轉(zhuǎn)義,避免這種沖突。
測(cè)試案例 示例對(duì)象UserEntry.java
public class UserEntry { /** * 名稱 */ private String name; /** * 內(nèi)嵌的用戶信息 */ @CsvEntry private User user; //Getter/Setter/ToString }
這里在需要內(nèi)嵌的對(duì)象上使用注解 @CsvEntry 表示需要進(jìn)行內(nèi)嵌的對(duì)象轉(zhuǎn)換。
User.java
其中 User 對(duì)象是原來(lái)使用的普通 java 對(duì)象
public class User { private String name; private int age; private float score; private double money; private boolean sex; private short level; private long id; private char status; private byte coin; //Getter/Setter/ToString }寫入測(cè)試
public void entryTest() { final String path = "src est esourcesentry.csv"; CsvWriteBs.newInstance(path) .write(buildEntryList()); }
buildEntryList()
負(fù)責(zé)對(duì)象構(gòu)建代碼,內(nèi)容如下:
/** * 用戶明細(xì)列表 * @return 明細(xì)列表 * @since 0.0.5 */ private ListbuildEntryList() { UserEntry userEntry = new UserEntry(); userEntry.name("test"); userEntry.user(buildCommonList().get(0)); return Collections.singletonList(userEntry); }
buildCommonList()
private ListbuildCommonList() { User user = new User(); short s = 4; byte b = 1; user.age(10) .name("你好") .id(1L) .score(60) .coin(b) .level(s) .money(200) .sex(true) .status("Y"); return Arrays.asList(user); }
生成文件效果
name,user test,你好:10:60.0:200.0:true:4:1:Y:1
如你所見,這里內(nèi)嵌對(duì)象的屬性使用了 : 進(jìn)行分隔。
讀取測(cè)試public void entryTest() { final String path = "src est esourcesentry.csv"; ListuserList = CsvReadBs.newInstance(path) .read(UserEntry.class); System.out.println(userList); }
輸出信息
[UserEntry{name="test", user=User{name="你好", age=10, score=60.0, money=200.0, sex=true, level=4, id=1, status=Y, coin=1}}]特殊字符轉(zhuǎn)義
在實(shí)際使用中,有時(shí)候我們會(huì)用到 ,|:=。
這幾個(gè)被使用的特殊字符。
如果你希望這些特殊的字符被正確的存取,那么可以使用 escape 屬性執(zhí)行。
特殊字符的轉(zhuǎn)換原始 | 轉(zhuǎn)義后 | |
---|---|---|
, | &CSV_COMMA; | |
` | ` | &CSV_OR; |
: | &CSV_COLON; | |
= | &CSV_EUQAL; |
下面演示一下如何使用
暫時(shí)轉(zhuǎn)義字符不支持自定義。
測(cè)試代碼 寫入測(cè)試public void escapeTest() { final String path = "src est esourcesescape.csv"; CsvWriteBs.newInstance(path) .escape(true) .write(buildUserEscapeList()); }
生成文件效果
name,map,nameList,user 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相關(guān)代碼
UserEscape.java
其中用到的對(duì)象為:
public class UserEscape { /** * 使用 , */ private String name; /** * 使用 map = */ private Mapmap; /** * 使用 | */ private List nameList; /** * 使用 : */ @CsvEntry private User user; //Getter & Setter & ToString() }
buildUserEscapeList()
構(gòu)建時(shí),特意使用了特殊的字符。
private List讀取測(cè)試buildUserEscapeList() { UserEscape escape = new UserEscape(); Map map = new HashMap<>(); map.put("key=key", "value=value"); User user = new User(); user.name("entry:name"); escape.name("one,one"); escape.nameList(Arrays.asList("one|one", "two|two")); escape.map(map); escape.user(user); return Collections.singletonList(escape); }
public void escapeTest() { final String path = "src est esourcesescape.csv"; ListuserList = CsvReadBs.newInstance(path) .escape(true) .read(UserEscape.class); System.out.println(userList); }
日志信息
[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}}]后續(xù)設(shè)計(jì) 更豐富的類型支持
支持更多的 java 常見類型。
更靈活的配置比如支持用戶自定義轉(zhuǎn)義字符
支持文件的寫入模式等等。
開源地址csv
可以查看相關(guān)代碼。
為了便于其他人閱讀和使用,代碼擁有詳細(xì)的注釋。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77856.html
摘要:基于注解生成加簽驗(yàn)簽。是否寫入頭,建議第一次寫入指定,避免中文亂碼指定文件編碼默認(rèn)不進(jìn)行字段排序無(wú)待寫入的文件列表方法默認(rèn)值說(shuō)明必填創(chuàng)建實(shí)例,并且指定待讀取文件路徑。 csv 基于 java 注解生成加簽驗(yàn)簽 csv。 開源地址: github csv) 創(chuàng)作原由 以前覺得 csv 文件的多寫非常簡(jiǎn)單,就懶得封裝。 最近一個(gè)月寫了兩次 csv 文件相關(guān)的東西,發(fā)現(xiàn)要處理的細(xì)節(jié)還是有的,...
摘要:集合類有時(shí)候?qū)ο笾袝?huì)包含數(shù)組等常見集合。為了存儲(chǔ)的便利性,默認(rèn)提供集合的相關(guān)支持。特性和普通字段保持一致,如果指定注解轉(zhuǎn)換,則以注解為準(zhǔn)。集合使用進(jìn)行分隔,其中的分隔,用到了。在使用時(shí)要注意,不要包含上述的符號(hào),否則會(huì)出現(xiàn)解析錯(cuò)亂。 集合類 有時(shí)候?qū)ο笾袝?huì)包含數(shù)組、Map、Collection 等常見集合。 為了存儲(chǔ)的便利性,默認(rèn)提供集合的相關(guān)支持。 特性和普通字段保持一致,如果指定注...
摘要:特性支持過程式編程基于字節(jié)碼的代理重試基于注解的重試,允許自定義注解無(wú)縫接入接口與注解的統(tǒng)一解決與中的不足之處設(shè)計(jì)目的綜合了和的優(yōu)勢(shì)?;谧止?jié)碼實(shí)現(xiàn)的代理重試,可以不依賴。提供基于代碼模式字節(jié)碼增強(qiáng)實(shí)現(xiàn)的方式。 Sisyphus 支持過程式編程和注解編程的 java 重試框架。 特性 支持 fluent 過程式編程 基于字節(jié)碼的代理重試 基于注解的重試,允許自定義注解 無(wú)縫接入 sp...
摘要:在結(jié)構(gòu)上引入了頭結(jié)點(diǎn)和尾節(jié)點(diǎn),他們分別指向隊(duì)列的頭和尾,嘗試獲取鎖入隊(duì)服務(wù)教程在它提出十多年后的今天,已經(jīng)成為最重要的應(yīng)用技術(shù)之一。隨著編程經(jīng)驗(yàn)的日積月累,越來(lái)越感覺到了解虛擬機(jī)相關(guān)要領(lǐng)的重要性。 JVM 源碼分析之 Jstat 工具原理完全解讀 http://click.aliyun.com/m/8315/ JVM 源碼分析之 Jstat 工具原理完全解讀 http:...
摘要:甲乙交易活動(dòng)不需要雙方見面,避免了雙方的互不信任造成交易失敗的問題。這就是的核心思想。統(tǒng)一配置,便于修改。帶參數(shù)的構(gòu)造函數(shù)創(chuàng)建對(duì)象首先,就要提供帶參數(shù)的構(gòu)造函數(shù)接下來(lái),關(guān)鍵是怎么配置文件了。 前言 前面已經(jīng)學(xué)習(xí)了Struts2和Hibernate框架了。接下來(lái)學(xué)習(xí)的是Spring框架...本博文主要是引入Spring框架... Spring介紹 Spring誕生: 創(chuàng)建Spring的...
閱讀 1339·2021-11-25 09:43
閱讀 751·2021-11-18 10:02
閱讀 2877·2021-09-07 09:59
閱讀 2757·2021-08-30 09:44
閱讀 2928·2019-08-30 13:17
閱讀 2317·2019-08-29 12:17
閱讀 1681·2019-08-28 17:57
閱讀 1289·2019-08-26 14:04