中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于 java 注解的 csv 讀寫框架更加簡單靈活

發布時間:2020-07-14 10:46:09 來源:網絡 閱讀:137555 作者:葉止水ryo 欄目:編程語言

CSV

基于 java 注解的 csv 讀寫框架。

相關框架

Apache commons-csv

super-csv

簡單看了下,這兩個框架提供的特性都非常的基礎。

創作原由

以前覺得 csv 文件的讀寫非常簡單,就懶得封裝。

最近一個月寫了兩次 csv 文件相關的東西,發現要處理的細節還是有的,還浪費比較多的時間。

比如:

  1. UTF-8 中文編碼使用 excel 打開亂碼,因為缺少 BOM 頭。

  2. 不同類型字段轉化為字符串,順序的指定,head 頭的指定,如果手寫都會很繁瑣。

  3. 讀取的時候最后 , 后無元素,split 會缺失等。

為了解決上述問題,此框架應運而生。

特性

  • Fluent 流式寫法

  • 基于 java 注解,支持自定義的轉換和靈活配置

  • 內置 8 大基本類型以及 String 類型轉換

  • 解決 Excel 直接打開,utf-8 亂碼問題

  • 支持集合、數組、Map 的存取

  • 支持對象中內嵌其他對象

  • 支持特殊字符轉義

變更日志

CHANGE_LOG.md

開源地址

csv

快速開始

環境

jdk7+

maven 3.x

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>csv</artifactId>
    <version>0.0.6</version>
</dependency>

示例代碼

  • 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<User> 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\\test\\resources\\common.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\\test\\resources\\common.csv";
    List<User> userList = 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 文件讀取引導類

CsvWriteBs

方法 默認值 說明
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<T> list) 待寫入的文件列表
escape false 是否進行特殊字符的轉換

CsvReadBs

方法 默認值 說明
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 是否進行特殊字符的轉換

Csv 注解

注解屬性說明

用于待處理對象的字段上。

    /**
     * 字段顯示名稱
     * 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<Date> {

    @Override
    public String convert(Date value) {
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        return dateFormat.format(value);
    }

}
  • ReadDateConvert
public class ReadDateConvert implements IReadConverter<Date> {

    @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\\test\\resources\\annotation.csv";
    CsvWriteBs.newInstance(path)
            .write(buildAnnotationList());
}

其中列表構建:

/**
 * 構建基于注解的測試列表
 * @return 列表
 */
private List<UserAnnotation> buildAnnotationList() {
    UserAnnotation user = new UserAnnotation();
    user.name("你好")
            .password("123")
            .birthday(new Date());
    return Arrays.asList(user);
}
  • 生成文件內容
名稱,生日
你好,20190603

讀取文件測試

public void annotationTest() {
     final String path = "src\\test\\resources\\annotation.csv";
     List<UserAnnotation> userList = 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<String> lists;

    private Map<String, String> maps;

    private Set<String> sets;

    //Getter/Setter/toString()
}

存儲

  • 待存儲對象的構建
/**
 * 構建基于集合的測試列表
 * @return 列表
 * @since 0.0.3
 */
private List<UserCollection> buildCollectionList() {
    UserCollection user = new UserCollection();
    String[] arrays = new String[]{"a", "b", "c"};
    LinkedList<String> lists = new LinkedList<>(Arrays.asList(arrays));
    Map<String, String> maps = new HashMap<>();
    maps.put("key", "value");
    maps.put("key2", "value2");
    Set<String> 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\\test\\resources\\collection.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\\test\\resources\\collection.csv";
    List<UserCollection> userList = 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\\test\\resources\\entry.csv";
    CsvWriteBs.newInstance(path)
            .write(buildEntryList());
}
  • buildEntryList()

負責對象構建代碼,內容如下:

/**
 * 用戶明細列表
 * @return 明細列表
 * @since 0.0.5
 */
private List<UserEntry> buildEntryList() {
    UserEntry userEntry = new UserEntry();
    userEntry.name("test");
    userEntry.user(buildCommonList().get(0));
    return Collections.singletonList(userEntry);
}
  • buildCommonList()
private List<User> 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);
}

生成文件效果

name,user
test,你好:10:60.0:200.0:true:4:1:Y:1

如你所見,這里內嵌對象的屬性使用了 : 進行分隔。

讀取測試

public void entryTest() {
    final String path = "src\\test\\resources\\entry.csv";
    List<UserEntry> userList = 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\\test\\resources\\escape.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 Map<String, String> map;

    /**
     * 使用 |
     */
    private List<String> nameList;

    /**
     * 使用 :
     */
    @CsvEntry
    private User user;

    //Getter & Setter & ToString()
}
  • buildUserEscapeList()

構建時,特意使用了特殊的字符。

private List<UserEscape> buildUserEscapeList() {
    UserEscape escape = new UserEscape();
    Map<String, String> 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\\test\\resources\\escape.csv";
    List<UserEscape> userList = 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

可以查看相關代碼。

為了便于其他人閱讀和使用,代碼擁有詳細的注釋。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阜康市| 奉化市| 恩施市| 鲁甸县| 广宁县| 江西省| 隆德县| 长葛市| 招远市| 丽江市| 秦皇岛市| 安西县| 靖安县| 晋宁县| 阿克陶县| 平顶山市| 赣州市| 宁远县| 平南县| 浦北县| 潍坊市| 广州市| 汉源县| 慈利县| 甘谷县| 上蔡县| 安泽县| 盐池县| 雷州市| 东乡县| 叶城县| 夏津县| 富宁县| 沈阳市| 安康市| 遂川县| 建水县| 舟曲县| 盘锦市| 淄博市| 平远县|