摘要:創作原由以前覺得文件的讀寫非常簡單,就懶得封裝。為了解決上述問題,此框架應運而生。寫入文件其中列表構建構建基于注解的測試列表列表你好生成文件內容名稱生日你好讀取文件測試日志信息你好集合類有時候對象中會包含數組等常見集合。
CSV
基于 java 注解的 csv 讀寫框架。
相關框架Apache commons-csv
super-csv
簡單看了下,這兩個框架提供的特性都非常的基礎。
創作原由以前覺得 csv 文件的讀寫非常簡單,就懶得封裝。
最近一個月寫了兩次 csv 文件相關的東西,發現要處理的細節還是有的,還浪費比較多的時間。
比如:
UTF-8 中文編碼使用 excel 打開亂碼,因為缺少 BOM 頭。
不同類型字段轉化為字符串,順序的指定,head 頭的指定,如果手寫都會很繁瑣。
讀取的時候最后 , 后無元素,split 會缺失等。
為了解決上述問題,此框架應運而生。
特性Fluent 流式寫法
基于 java 注解,支持自定義的轉換和靈活配置
內置 8 大基本類型以及 String 類型轉換
解決 Excel 直接打開,utf-8 亂碼問題
支持集合、數組、Map 的存取
支持對象中內嵌其他對象
支持特殊字符轉義
變更日志CHANGE_LOG.md
開源地址csv
快速開始 環境jdk7+
maven 3.x
maven 引入示例代碼com.github.houbb csv 0.0.6
User.java
演示基本類型的轉換
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() }
對象列表構建
/** * 構建通用測試列表 * @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); }
測試代碼
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}]引導類 為什么需要引導類
為了靈活的配置和默認配置并存,使用工具類會大大降低靈活性。
為了用戶使用的便利性,和后期拓展的靈活性。
引導類CSV 有兩個引導類:
名稱 | 作用 |
---|---|
CsvWriteBs | csv 文件寫入引導類 |
CsvReadBs | csv 文件讀取引導類 |
方法 | 默認值 | 說明 |
---|---|---|
newInstance(final String path) | 必填 | 創建實例,并且指定待寫入文件路徑。 |
path (final String path) | 配置文件路徑,只有重新指定 path 路徑時需要調用。 | |
writeHead(boolean writeBom) | true | 是否寫入 head 頭,如果想指定名稱,可以結合注解。只有無 head 信息時,會寫入。 |
writeBom(boolean writeBom) | true | 是否寫入 UTF8 BOM 頭,只有文件為空時才會寫入。 |
charset(String charset) | UTF-8 | 指定文件編碼 |
sort(ISort sort) | NoSort | 默認不進行字段排序 |
write(List |
無 | 待寫入的文件列表 |
escape | false | 是否進行特殊字符的轉換 |
方法 | 默認值 | 說明 |
---|---|---|
newInstance(final String path) | 必填 | 創建實例,并且指定待讀取文件路徑。 |
path (final String path) | 配置文件路徑,只有重新指定 path 路徑時需要調用。 | |
charset(String charset) | UTF-8 | 指定文件編碼 |
sort(ISort sort) | NoSort | 默認不進行字段排序 |
startIndex(int startIndex) | 1 | 文件的第二行,默認第一行是 head |
endIndex(int endIndex) | 文件的最后一行 | |
escape | false | 是否進行特殊字符的轉換 |
用于待處理對象的字段上。
/** * 字段顯示名稱 * 1. 默認使用 field.name * @return 顯示名稱 */ String label() default ""; /** * 讀取是否需要 * @return 是 */ boolean readRequire() default true; /** * 寫入是否需要 * @return 是 */ boolean writeRequire() default true; /** * 讀取轉換 * @return 處理實現類 */ Class extends IReadConverter> readConverter() default CommonReadConverter.class; /** * 寫入轉換 * @return 處理實現類 */ Class extends IWriteConverter> writeConverter() default StringWriteConverter.class;屬性概覽表
屬性 | 默認值 | 說明 |
---|---|---|
label | 字段名稱 | 用于 csv 頭生成 |
readRequire | true | 是否需要從 csv 文件讀取 |
writeRequire | true | 當前字段是否需要寫入 csv 文件 |
readConverter | CommonReadConverter | 將 csv 中的字符串轉化為當前字段類型,支持 8 大基本類型+String |
writeConverter | StringWriteConverter | 直接調用當前字段值 toString() 方法,null 直接為空字符串 |
其中 readConverter/writeConverter 支持用戶自定義
字段注解 對象定義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
使我們自定義的針對 Date 的轉換實現。
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()); }
其中列表構建:
/** * 構建基于注解的測試列表 * @return 列表 */ private ListbuildAnnotationList() { UserAnnotation user = new UserAnnotation(); user.name("你好") .password("123") .birthday(new Date()); return Arrays.asList(user); }
生成文件內容
名稱,生日 你好,20190603讀取文件測試
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}]集合類
有時候對象中會包含數組、Map、Collection 等常見集合。
為了存儲的便利性,默認提供集合的相關支持。
特性和普通字段保持一致,如果指定注解轉換,則以注解為準。
使用示例UserCollection.java
用于演示集合的對象
public class UserCollection { private String[] arrays; private LinkedList存儲lists; private Map maps; private Set sets; //Getter/Setter/toString() }
待存儲對象的構建
/** * 構建基于集合的測試列表 * @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); }
執行存儲
public void collectionTest() { final String path = "src est esourcescollection.csv"; CsvWriteBs.newInstance(path) .write(buildCollectionList()); }
存儲效果
?arrays,lists,maps,sets a|b,a|b|c,key2=value2|key=value,set1|set2讀取
測試類
public void collectionTest() { final String path = "src est esourcescollection.csv"; ListuserList = CsvReadBs.newInstance(path) .read(UserCollection.class); System.out.println(userList); }
測試日志
[UserCollection{arrays=[a, b], lists=[a, b, c], maps={key=value, key2=value2}, sets=[set2, set1]}]注意
為了保證 csv 以 , 分隔的統一性。
集合使用 | 進行分隔,其中 map 的 key/value 分隔,用到了 =。
在使用時要注意,不要包含上述的符號,否則會出現解析錯亂。
ps: 如果確實用到這些字符,可以見后面的特殊字符轉義功能。
支持內嵌對象有時候我們希望像使用 mongoDB 一樣,非常方便的存取 csv 的嵌套對象。
對于普通的 csv 都沒有實現這個特性,本次做了一個嘗試,支持內嵌對象的存取。
取舍就像 csv 的簡單,需要用到符號 , 一樣。
內嵌對象為了不破壞 csv 的規范,使用了符號 :。
換言之,也就是對象內容中不能使用這個符號。
后期會針對出現的符號進行轉義,避免這種沖突。
測試案例 示例對象UserEntry.java
public class UserEntry { /** * 名稱 */ private String name; /** * 內嵌的用戶信息 */ @CsvEntry private User user; //Getter/Setter/ToString }
這里在需要內嵌的對象上使用注解 @CsvEntry 表示需要進行內嵌的對象轉換。
User.java
其中 User 對象是原來使用的普通 java 對象
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 }寫入測試
public void entryTest() { final String path = "src est esourcesentry.csv"; CsvWriteBs.newInstance(path) .write(buildEntryList()); }
buildEntryList()
負責對象構建代碼,內容如下:
/** * 用戶明細列表 * @return 明細列表 * @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
如你所見,這里內嵌對象的屬性使用了 : 進行分隔。
讀取測試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}}]特殊字符轉義
在實際使用中,有時候我們會用到 ,|:=。
這幾個被使用的特殊字符。
如果你希望這些特殊的字符被正確的存取,那么可以使用 escape 屬性執行。
特殊字符的轉換原始 | 轉義后 | |
---|---|---|
, | &CSV_COMMA; | |
` | ` | &CSV_OR; |
: | &CSV_COLON; | |
= | &CSV_EUQAL; |
下面演示一下如何使用
暫時轉義字符不支持自定義。
測試代碼 寫入測試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相關代碼
UserEscape.java
其中用到的對象為:
public class UserEscape { /** * 使用 , */ private String name; /** * 使用 map = */ private Mapmap; /** * 使用 | */ private List nameList; /** * 使用 : */ @CsvEntry private User user; //Getter & Setter & ToString() }
buildUserEscapeList()
構建時,特意使用了特殊的字符。
private List讀取測試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}}]后續設計 更豐富的類型支持
支持更多的 java 常見類型。
更靈活的配置比如支持用戶自定義轉義字符
支持文件的寫入模式等等。
開源地址csv
可以查看相關代碼。
為了便于其他人閱讀和使用,代碼擁有詳細的注釋。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77856.html
摘要:基于注解生成加簽驗簽。是否寫入頭,建議第一次寫入指定,避免中文亂碼指定文件編碼默認不進行字段排序無待寫入的文件列表方法默認值說明必填創建實例,并且指定待讀取文件路徑。 csv 基于 java 注解生成加簽驗簽 csv。 開源地址: github csv) 創作原由 以前覺得 csv 文件的多寫非常簡單,就懶得封裝。 最近一個月寫了兩次 csv 文件相關的東西,發現要處理的細節還是有的,...
摘要:集合類有時候對象中會包含數組等常見集合。為了存儲的便利性,默認提供集合的相關支持。特性和普通字段保持一致,如果指定注解轉換,則以注解為準。集合使用進行分隔,其中的分隔,用到了。在使用時要注意,不要包含上述的符號,否則會出現解析錯亂。 集合類 有時候對象中會包含數組、Map、Collection 等常見集合。 為了存儲的便利性,默認提供集合的相關支持。 特性和普通字段保持一致,如果指定注...
摘要:特性支持過程式編程基于字節碼的代理重試基于注解的重試,允許自定義注解無縫接入接口與注解的統一解決與中的不足之處設計目的綜合了和的優勢。基于字節碼實現的代理重試,可以不依賴。提供基于代碼模式字節碼增強實現的方式。 Sisyphus 支持過程式編程和注解編程的 java 重試框架。 特性 支持 fluent 過程式編程 基于字節碼的代理重試 基于注解的重試,允許自定義注解 無縫接入 sp...
摘要:在結構上引入了頭結點和尾節點,他們分別指向隊列的頭和尾,嘗試獲取鎖入隊服務教程在它提出十多年后的今天,已經成為最重要的應用技術之一。隨著編程經驗的日積月累,越來越感覺到了解虛擬機相關要領的重要性。 JVM 源碼分析之 Jstat 工具原理完全解讀 http://click.aliyun.com/m/8315/ JVM 源碼分析之 Jstat 工具原理完全解讀 http:...
摘要:甲乙交易活動不需要雙方見面,避免了雙方的互不信任造成交易失敗的問題。這就是的核心思想。統一配置,便于修改。帶參數的構造函數創建對象首先,就要提供帶參數的構造函數接下來,關鍵是怎么配置文件了。 前言 前面已經學習了Struts2和Hibernate框架了。接下來學習的是Spring框架...本博文主要是引入Spring框架... Spring介紹 Spring誕生: 創建Spring的...
閱讀 1330·2021-11-25 09:43
閱讀 738·2021-11-18 10:02
閱讀 2861·2021-09-07 09:59
閱讀 2747·2021-08-30 09:44
閱讀 2920·2019-08-30 13:17
閱讀 2305·2019-08-29 12:17
閱讀 1673·2019-08-28 17:57
閱讀 1281·2019-08-26 14:04