Java中csv文件讀寫超詳細(xì)分析
一、txt、csv、tsv文件
txt、csv、tsv都屬于文本文件
| 文件類型 | 英文全稱 | 名稱 | 分隔符 | 描述 |
|---|---|---|---|---|
| txt | text | 文本類型 | 沒有明確要求 | 可以有分隔符,也可以沒有 |
| csv | Comma-separated values | 逗號(hào)分隔值類型 | 半角逗號(hào):',' | csv是txt的特殊類型 |
| tsv | Tab-separated values | 制表符分隔值 | 制表符:'\t' | tsv是txt的特殊類型 |
csv又有叫做Char-separated values(字符分隔值類型),通過字符值進(jìn)行分隔。
但因?yàn)榘虢嵌禾?hào)在數(shù)據(jù)中出現(xiàn)的的可能性比較大,所以經(jīng)常會(huì)使用文本包裝符來標(biāo)識(shí)逗號(hào)為數(shù)據(jù)中的一部分,或者直接使用其它特殊符號(hào)作為分隔符。
二、csv文件規(guī)范
- 每一行記錄位于一個(gè)單獨(dú)的行上,用回車換行符CRLF(\r\n)分割。
- 文件中的最后一行記錄可以有結(jié)尾回車換行符,也可以沒有。
- 第一行可以存在一個(gè)可選的標(biāo)題頭,格式和普通記錄行的格式一樣。標(biāo)題頭要包含文件記錄字段對(duì)應(yīng)的名稱,應(yīng)該有和記錄字段一樣的數(shù)量。
- 在標(biāo)題頭行和普通行每行記錄中,會(huì)存在一個(gè)或多個(gè)由半角逗號(hào)(,)分隔的字段。整個(gè)文件中每行應(yīng)包含相同數(shù)量的字段,空格也是字段的一部分,不應(yīng)被忽略。每一行記錄最后一個(gè)字段后不能跟逗號(hào)。(通常用逗號(hào)分隔,也有其他字符分隔的CSV,需事先約定)
- 每個(gè)字段可用也可不用半角雙引號(hào)(")(文本包裝符)括起來(如Microsoft的Excel就根本不用雙引號(hào))。如果字段沒有用引號(hào)括起來,那么該字段內(nèi)部不能出現(xiàn)雙引號(hào)字符。
- 字段中若包含回車換行符、雙引號(hào)或者逗號(hào),該字段需要用雙引號(hào)括起來。
- 如果用雙引號(hào)括字段,那么出現(xiàn)在字段內(nèi)的雙引號(hào)前必須再加一個(gè)雙引號(hào)進(jìn)行轉(zhuǎn)義。
三、csv使用場景
csv文件經(jīng)常用于導(dǎo)出大批量數(shù)據(jù)(csv比excel更輕量級(jí),更適合大批量數(shù)據(jù))。
csv與excel對(duì)比:
- csv只能用于存儲(chǔ)純文本內(nèi)容,excel不僅支持純文本內(nèi)容還支持二進(jìn)制數(shù)據(jù)
- csv可以看做是excel的輕量級(jí)簡單版實(shí)現(xiàn),excel比csv更加強(qiáng)大
- csv文件可以被excel軟件直接打開,csv文件一般用于表格數(shù)據(jù)的傳輸
四、Java中的csv類庫
java中的csv的類庫主要有以下幾類:
- javacsv:javacsv在2014-12-10就不維護(hù)了
- opencsv:opencsv是apache的項(xiàng)目,至今仍在維護(hù)
1. javacsv
2. opencsv
opencsv是一個(gè)用Java來分析和生成csv文件的框架。通常用來bean的寫入csv文件和從csv文件讀出bean,并支持注解的方式。
maven依賴:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.6</version>
</dependency>寫入器
| 名稱 | 描述 |
|---|---|
| CSVWriter | 簡單的CSV寫入器 |
| CSVParserWriter | 通過CSVParser解析數(shù)據(jù)的寫入器 |
| StatefulBeanToCsv | 直接將bean寫入CSV的寫入器 |
讀取器
| 名稱 | 描述 |
|---|---|
| CSVReader | 簡單的CSV讀取器 |
| CsvToBean | CSV讀取為bean的讀取器 |
| CSVReaderHeaderAware |
解析器
| 名稱 | 描述 |
|---|---|
| CSVParser | 簡單的CSV解析器 |
| RFC4180Parser | 基于RFC4180規(guī)范的解析器 |
注解
| 注解 | 描述 | 主要屬性 |
|---|---|---|
| @CsvBindByName | 按表頭名稱綁定 | required:必須字段,默認(rèn)為false.該字段為空拋異常 column:對(duì)象列標(biāo)題名稱 |
| @CsvBindByPosition | 按位置綁定 | required:必須字段,默認(rèn)為false.該字段為空拋異常 position:位置索引 |
| @CsvCustomBindByName | 與CsvBindByName相同,但必須提供自己的數(shù)據(jù)轉(zhuǎn)換類 | required:必須字段,默認(rèn)為false.該字段為空拋異常 column:對(duì)象列標(biāo)題名稱 converter:轉(zhuǎn)換器 |
| @CsvCustomBindByPosition | 與CsvBindByPosition相同,但必須提供自己的數(shù)據(jù)轉(zhuǎn)換類 | required:必須字段,默認(rèn)為false.該字段為空拋異常 column:對(duì)象列標(biāo)題名稱 converter:轉(zhuǎn)換器 |
| @CsvBindAndJoinByName | 應(yīng)用于MultiValuedMap集合類型的bean字段,通過標(biāo)題名稱綁定 | required:必須字段,默認(rèn)為false.該字段為空拋異常 column:對(duì)象列標(biāo)題名稱 converter:轉(zhuǎn)換器 mapType:集合類型 elementTyp:元素類型 |
| @CsvBindAndJoinByPosition | 應(yīng)用于MultiValuedMap集合類型的bean字段,通過位置索引綁定 | required:必須字段,默認(rèn)為false.該字段為空拋異常 position:位置索引 converter:轉(zhuǎn)換器 mapType:集合類型 elementTyp:元素類型 |
| @CsvBindAndSplitByName | 應(yīng)用于Collection集合類型的bean字段,通過標(biāo)題名稱綁定 | required:必須字段,默認(rèn)為false.該字段為空拋異常 column:對(duì)象列標(biāo)題名稱 converter:轉(zhuǎn)換器 mapType:集合類型 elementTyp:元素類型 splitOn: |
| @CsvBindAndSplitByPosition | 應(yīng)用于Collection集合類型的bean字段,通過位置索引綁定 | required:必須字段,默認(rèn)為false.該字段為空拋異常 position:位置索引 converter:轉(zhuǎn)換器 mapType:集合類型 elementTyp:元素類型 splitOn: |
| @CsvDate | 應(yīng)用于日期/時(shí)間類型的bean字段,與上面相關(guān)的綁定注解結(jié)合使用 | value:日期格式,例如:yyyy-MM-dd |
| @CsvNumber | 應(yīng)用于數(shù)字類型的bean字段,與上面相關(guān)的綁定注解結(jié)合使用 | value:數(shù)字格式,例如:000.### |
映射策略

| 名稱 | 描述 | 重要方法 | 方法描述 |
|---|---|---|---|
| ColumnPositionMappingStrategy | 列位置映射策略,用于沒有頭文件(標(biāo)題行)的文件 | setColumnMapping(String… columnMapping | 設(shè)置要映射的列名集合,集合下標(biāo)即為列寫入順序 |
| HeaderColumnNameMappingStrategy | 標(biāo)題列名稱映射策略, | setColumnOrderOnWrite(Comparator writeOrder) | 通過比較器,設(shè)置列寫入順序 |
| HeaderColumnNameTranslateMappingStrategy | 標(biāo)題列名稱翻譯映射策略 bean的屬性名可以與csv列頭不一樣,通過指定map來映射。 | setColumnMapping(Map<String, String> columnMapping) | 設(shè)置標(biāo)題名與列名的映射 |
| FuzzyMappingStrategy |
① ColumnPositionMappingStrategy
使用該映射策略需要csv文件沒有標(biāo)題行。該策略通過設(shè)置列的下標(biāo)位置來指定列的順序,有兩種方式來設(shè)置列的下標(biāo):
- 通過CsvBindByPosition、CsvCustomBindByPosition、CsvBindAndJoinByPosition、CsvBindAndSplitByPosition注解來設(shè)置列的下標(biāo)
- 通過setColumnMapping(String… columnMapping)方法來設(shè)置列的下標(biāo)
② HeaderColumnNameMappingStrategy
該映射策略用于有標(biāo)題行的csv文件。該策略通過指定比較器來指定列的順序:
- 通過setColumnOrderOnWrite(Comparator writeOrder)指定比較器
關(guān)于標(biāo)題列的名稱:
- 默認(rèn)使用bean的字段名稱大寫作為標(biāo)題列的名稱
- 如果使用CsvBindByName、CsvCustomBindByName、CsvBindAndJoinByName、CsvBindAndSplitByName注解的column屬性指定列名稱,則使用該值,否則使用bean的字段名稱大寫作為標(biāo)題列的名稱
③ HeaderColumnNameTranslateMappingStrategy
該映射策略用于有標(biāo)題行的csv文件。該策略通過映射Map來指定標(biāo)題列名與bean的屬性名映射關(guān)系。
映射Map的key=標(biāo)題列名,value=bean的屬性名。
需要注意:
- 該映射策略只適用于讀取csv文件時(shí),指定標(biāo)題列名與bean的屬性名的映射關(guān)系
- 該映射策略不適用于寫入csv文件時(shí),指定bean的屬性名與標(biāo)題列名的映射關(guān)系(不要誤解)
過濾器
| 名稱 | 描述 |
|---|---|
| CsvToBeanFilter | 讀取時(shí)根據(jù)過濾規(guī)則過濾掉一些行 |
主要方法:boolean allowLine(String[] line)
- 入?yún)⒅械膌ine表示一行數(shù)據(jù)的集合
- 返回值為false的這行數(shù)據(jù)被將被過濾掉
構(gòu)建器
| 名稱 | 描述 |
|---|---|
| CSVWriterBuilder | CSV寫入構(gòu)建器,構(gòu)建CSVWriter或CSVParserWriter |
| StatefulBeanToCsvBuilder | 對(duì)象寫入CSV構(gòu)建器,構(gòu)建StatefulBeanToCsv |
| CSVReaderBuilder | CSV讀取構(gòu)建器,構(gòu)建CSVReader |
| CsvToBeanBuilder | CSV讀取對(duì)象構(gòu)建器,構(gòu)建CsvToBean |
| CSVReaderHeaderAwareBuilder | 構(gòu)建CSVReaderHeaderAware |
| CSVParserBuilder | CSV解析器構(gòu)造器,構(gòu)建CSVParser |
| RFC4180ParserBuilder | RFC4180解析器構(gòu)造器,構(gòu)建RFC4180Parser |
寫入方式
User類:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
public String userId;
public String userName;
public String sex;
}User1類:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User1 {
@CsvBindByPosition(position = 0)
public String userId;
@CsvBindByPosition(position = 1)
public String userName;
@CsvBindByPosition(position = 2)
public String sex;
}User2類:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User2 {
@CsvBindByName(column = "用戶ID")
public String userId;
@CsvBindByName(column = "用戶名")
public String userName;
@CsvBindByName(column = "性別")
public String sex;
}① 簡單的寫入
CSVWriter的主要參數(shù):
- Writer writer:指定需要寫入的源文件
- char separator:分隔符(默認(rèn)逗號(hào))
- char quotechar:文本邊界符(默認(rèn)雙引號(hào))
- 如果數(shù)據(jù)中包含分隔符,需要使用文本邊界符包裹數(shù)據(jù)。通常用雙引號(hào)、單引號(hào)或斜杠作為文本邊界符
- char escapechar:轉(zhuǎn)義字符(默認(rèn)雙引號(hào))
- String lineend:行分隔符(默認(rèn)為\n)
使用方法:
/**
* 簡單的寫入
* @throws Exception
*/
private static void csvWriter() throws Exception {
// 寫入位置
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
// 標(biāo)題行
String[] titleRow = {"用戶ID", "用戶名", "性別"};
// 數(shù)據(jù)行
ArrayList<String[]> dataRows = new ArrayList<>();
String[] dataRow1 = {"1", "張三", "男"};
String[] dataRow2 = {"2", "李四", "男"};
String[] dataRow3 = {"3", "翠花", "女"};
dataRows.add(dataRow1);
dataRows.add(dataRow2);
dataRows.add(dataRow3);
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName), Charset.forName("UTF-8"));
// 1. 通過new CSVWriter對(duì)象的方式直接創(chuàng)建CSVWriter對(duì)象
// CSVWriter csvWriter = new CSVWriter(writer);
// 2. 通過CSVWriterBuilder構(gòu)造器構(gòu)建CSVWriter對(duì)象
CSVWriter csvWriter = (CSVWriter) new CSVWriterBuilder(writer)
.build();
// 寫入標(biāo)題行
csvWriter.writeNext(titleRow, false);
// 寫入數(shù)據(jù)行
csvWriter.writeAll(dataRows, false);
csvWriter.close();
}demo.csv內(nèi)容:
用戶ID,用戶名,性別
1,張三,男
2,李四,男
3,翠花,女
② 基于位置映射的寫入
使用方法:
/**
* 基于位置映射的寫入
* @throws Exception
*/
private static void beanToCsvByPosition() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
List<User> list = new ArrayList<>();
list.add(new User("1", "張三", "男"));
list.add(new User("2", "李四", "男"));
list.add(new User("3", "翠花", "女"));
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName), Charset.forName("UTF-8"));
ColumnPositionMappingStrategy<User> strategy = new ColumnPositionMappingStrategy();
// 未指定的列不寫入
String[] columns = new String[] { "userId", "userName", "sex"};
strategy.setColumnMapping(columns);
strategy.setType(User.class);
// 如果需要標(biāo)題行,可這樣寫入
// CSVWriter csvWriter = (CSVWriter) new CSVWriterBuilder(writer)
// .build();
// String[] titleRow = {"用戶ID", "用戶名", "性別"};
// csvWriter.writeNext(titleRow, false);
StatefulBeanToCsv<User> statefulBeanToCsv = new StatefulBeanToCsvBuilder<User>(writer)
.withMappingStrategy(strategy)
.withApplyQuotesToAll(false)
.build();
statefulBeanToCsv.write(list);
writer.close();
}demo.csv內(nèi)容:
1,張三,男
2,李四,男
3,翠花,女
③ 基于CsvBindByPosition注解映射的寫入
使用方法:
/**
* 基于CsvBindByPosition注解映射的寫入
* @throws Exception
*/
private static void beanToCsvByPositionAnnotation() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
List<User1> list = new ArrayList<>();
list.add(new User1("1", "張三", "男"));
list.add(new User1("2", "李四", "男"));
list.add(new User1("3", "翠花", "女"));
// 未使用@CsvBindByPosition注解的列不寫入
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName), Charset.forName("UTF-8"));
// 如果需要標(biāo)題行,可這樣寫入
// CSVWriter csvWriter = (CSVWriter) new CSVWriterBuilder(writer)
// .build();
// String[] titleRow = {"用戶ID", "用戶名", "性別"};
// csvWriter.writeNext(titleRow, false);
StatefulBeanToCsv<User1> statefulBeanToCsv = new StatefulBeanToCsvBuilder<User1>(writer)
.withApplyQuotesToAll(false)
.build();
statefulBeanToCsv.write(list);
writer.close();
}demo.csv內(nèi)容:
1,張三,男
2,李四,男
3,翠花,女
④ 基于列名映射的寫入
使用方法:
/**
* 基于列名映射的寫入
* @throws Exception
*/
private static void beanToCsvByName() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
List<User> list = new ArrayList<>();
list.add(new User("1", "張三", "男"));
list.add(new User("2", "李四", "男"));
list.add(new User("3", "翠花", "女"));
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName), Charset.forName("UTF-8"));
// 可通過比較器指定列的順序
// 標(biāo)題行的列名默認(rèn)為bean的字段名大寫
HeaderColumnNameMappingStrategy<User> strategy = new HeaderColumnNameMappingStrategy<>();
HashMap<String, Integer> columnOrderMap = new HashMap<>();
columnOrderMap.put("USERID", 1);
columnOrderMap.put("SEX", 10);
columnOrderMap.put("USERNAME", 100);
strategy.setColumnOrderOnWrite(Comparator.comparingInt(column -> (columnOrderMap.getOrDefault(column, 0))));
strategy.setType(User.class);
StatefulBeanToCsv<User> statefulBeanToCsv = new StatefulBeanToCsvBuilder<User>(writer)
.withMappingStrategy(strategy)
.withApplyQuotesToAll(false)
.build();
statefulBeanToCsv.write(list);
writer.close();
}demo.csv內(nèi)容:
用戶ID,用戶名,性別
1,張三,男
2,李四,男
3,翠花,女
⑤ 基于CsvBindByName注解映射的寫入
使用方法:
/**
* 基于CsvBindByName注解映射的寫入
* @throws Exception
*/
private static void beanToCsvByNameAnnotation() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
List<User2> list = new ArrayList<>();
list.add(new User2("1", "張三", "男"));
list.add(new User2("2", "李四", "男"));
list.add(new User2("3", "翠花", "女"));
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName), Charset.forName("UTF-8"));
// 可通過比較器指定列的順序
// 通過CsvBindByName注解的column屬性,指定標(biāo)題行的列名
HeaderColumnNameMappingStrategy<User2> strategy = new HeaderColumnNameMappingStrategy<>();
// 注意這里的key是指的標(biāo)題行的列名
HashMap<String, Integer> columnOrderMap = new HashMap<>();
columnOrderMap.put("用戶ID", 1);
columnOrderMap.put("用戶名", 10);
columnOrderMap.put("性別", 100);
strategy.setColumnOrderOnWrite(Comparator.comparingInt(column -> (columnOrderMap.getOrDefault(column, 0))));
strategy.setType(User2.class);
StatefulBeanToCsv<User2> statefulBeanToCsv = new StatefulBeanToCsvBuilder<User2>(writer)
.withMappingStrategy(strategy)
.withApplyQuotesToAll(false)
.build();
statefulBeanToCsv.write(list);
writer.close();
}demo.csv內(nèi)容:
用戶ID,用戶名,性別
1,張三,男
2,李四,男
3,翠花,女
讀取方式
通過簡單的寫入寫入的數(shù)據(jù)
① 簡單的讀取
使用方法:
/**
* 簡單的讀取
* @throws Exception
*/
private static void csvReader() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), Charset.forName("UTF-8"));
CSVReader csvReader = new CSVReaderBuilder(reader).build();
List<String[]> list = csvReader.readAll();
for (String[] strings : list) {
System.out.println(JSON.toJSONString(strings));
}
csvReader.close();
}控制臺(tái)日志:
["用戶ID","用戶名","性別"]
["1","張三","男"]
["2","李四","男"]
["3","翠花","女"]
② 基于位置映射的讀取
通過基于位置映射的寫入寫入的數(shù)據(jù)
使用方法:
/**
* 基于位置映射的讀取
* @throws Exception
*/
private static void csvToBeanByPosition() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), Charset.forName("UTF-8"));
// 不需要標(biāo)題行,列的順序通過列位置映射指定
ColumnPositionMappingStrategy<User> strategy = new ColumnPositionMappingStrategy();
String[] columns = new String[] { "userId", "userName", "sex"};
strategy.setColumnMapping(columns);
strategy.setType(User.class);
CsvToBean<User> csvToBean = new CsvToBeanBuilder<User>(reader)
.withMappingStrategy(strategy)
.build();
List<User> list = csvToBean.parse();
for (User user : list) {
System.out.println(JSON.toJSONString(user));
}
reader.close();
}控制臺(tái)日志:
{"sex":"男","userId":"1","userName":"張三"}
{"sex":"男","userId":"2","userName":"李四"}
{"sex":"女","userId":"3","userName":"翠花"}
③ 基于CsvBindByPosition注解映射的讀取
通過基于CsvBindByPosition注解映射的寫入寫入的數(shù)據(jù)
使用方法:
/**
* 基于CsvBindByPosition注解映射的讀取
* @throws Exception
*/
private static void csvToBeanByPositionAnnotation() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), Charset.forName("UTF-8"));
// 不需要標(biāo)題行,列的順序通過CsvBindByPosition注解的position屬性指定
CsvToBean<User1> csvToBean = new CsvToBeanBuilder<User1>(reader)
.withType(User1.class)
.build();
List<User1> list = csvToBean.parse();
for (User1 user : list) {
System.out.println(JSON.toJSONString(user));
}
reader.close();
}控制臺(tái)日志:
{"sex":"男","userId":"1","userName":"張三"}
{"sex":"男","userId":"2","userName":"李四"}
{"sex":"女","userId":"3","userName":"翠花"}
④ 基于列名映射的讀取
通過基于列名映射的寫入寫入的數(shù)據(jù)
使用方法:
/**
* 基于列名映射的讀取
* @throws Exception
*/
private static void csvToBeanByName() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), Charset.forName("UTF-8"));
// bean的字段名稱大寫為標(biāo)題列名
CsvToBean<User> csvToBean = new CsvToBeanBuilder<User>(reader)
.withType(User.class)
.build();
List<User> list = csvToBean.parse();
for (User user : list) {
System.out.println(JSON.toJSONString(user));
}
reader.close();
}控制臺(tái)日志:
{"sex":"男","userId":"1","userName":"張三"}
{"sex":"男","userId":"2","userName":"李四"}
{"sex":"女","userId":"3","userName":"翠花"}
⑤ 基于CsvBindByName注解映射的讀取
通過基于CsvBindByName注解映射的寫入寫入的數(shù)據(jù)
使用方法:
private static void csvToBeanByNameAnnotation() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), Charset.forName("UTF-8"));
// CsvBindByName注解的column屬性為標(biāo)題列名
CsvToBean<User2> csvToBean = new CsvToBeanBuilder<User2>(reader)
.withType(User2.class)
.build();
List<User2> list = csvToBean.parse();
for (User2 user : list) {
System.out.println(JSON.toJSONString(user));
}
reader.close();
}控制臺(tái)日志:
{"sex":"男","userId":"1","userName":"張三"}
{"sex":"男","userId":"2","userName":"李四"}
{"sex":"女","userId":"3","userName":"翠花"}
⑥ 基于列名轉(zhuǎn)換映射的讀取
通過基于CsvBindByName注解映射的讀取寫入的數(shù)據(jù)
使用方法:
public class MyCsvToBeanFilter implements CsvToBeanFilter {
@Override
public boolean allowLine(String[] line) {
// 過濾掉用戶名為李四的行
if("李四".equals(line[1])){
return false;
}
return true;
}
} /**
* 基于列名轉(zhuǎn)換映射的讀取
* @throws Exception
*/
private static void csvToBeanByColumnNameTranslateMapping() throws Exception {
String classpath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String fileName = classpath+"test/demo.csv";
InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), Charset.forName("UTF-8"));
// 指定標(biāo)題列名和bean列名映射關(guān)系
HeaderColumnNameTranslateMappingStrategy<User> strategy = new HeaderColumnNameTranslateMappingStrategy<>();
// key:標(biāo)題列名,value:bean的屬性名
HashMap<String, String> columnMappingMap = new HashMap<>();
columnMappingMap.put("用戶ID", "userId");
columnMappingMap.put("性別", "sex");
columnMappingMap.put("用戶名", "userName");
strategy.setColumnMapping(columnMappingMap);
strategy.setType(User.class);
CsvToBean<User> csvToBean = new CsvToBeanBuilder<User>(reader)
.withMappingStrategy(strategy)
.withFilter(new MyCsvToBeanFilter())
.withIgnoreField(User2.class, User2.class.getField("userId"))// 忽略u(píng)serId屬性
.build();
List<User> list = csvToBean.parse();
for (User user : list) {
System.out.println(JSON.toJSONString(user));
}
reader.close();
}控制臺(tái)日志:
{"sex":"男","userName":"張三"}
{"sex":"女","userName":"翠花"}3. commons-csv
4. hutool CsvUtil(擴(kuò)展)
總結(jié)
到此這篇關(guān)于Java中csv文件讀寫超詳細(xì)分析的文章就介紹到這了,更多相關(guān)Java csv文件讀寫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot對(duì)Filter過濾器中的異常進(jìn)行全局處理方案詳解
這篇文章主要介紹了SpringBoot對(duì)Filter過濾器中的異常進(jìn)行全局處理,在SpringBoot中我們通過 @ControllerAdvice 注解和 @ExceptionHandler注解注冊(cè)了全局異常處理器,需要的朋友可以參考下2023-09-09
Java實(shí)現(xiàn)駝峰與下劃線互轉(zhuǎn)的方法
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)駝峰與下劃線互轉(zhuǎn)的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04
Java中g(shù)etSuperclass()方法的使用與原理解讀
文章介紹了Java中的getSuperclass()方法,該方法用于獲取一個(gè)類的直接父類,通過理解其使用方式、工作原理以及實(shí)際應(yīng)用場景,可以更好地利用反射機(jī)制處理類的繼承關(guān)系,實(shí)現(xiàn)動(dòng)態(tài)類型檢查、類加載以及序列化等功能2025-01-01
SpringBoot整合mybatis使用Druid做連接池的方式
這篇文章主要介紹了SpringBoot整合mybatis使用Druid做連接池的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
SpringBoot如何監(jiān)聽redis?Key變化事件案例詳解
項(xiàng)目中需要監(jiān)聽redis的一些事件比如鍵刪除,修改,過期等,下面這篇文章主要給大家介紹了關(guān)于SpringBoot如何監(jiān)聽redis?Key變化事件的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Java Swing JCheckBox復(fù)選框的實(shí)現(xiàn)方法
這篇文章主要介紹了Java Swing JCheckBox復(fù)選框的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Java經(jīng)典設(shè)計(jì)模式之責(zé)任鏈模式原理與用法詳解
這篇文章主要介紹了Java經(jīng)典設(shè)計(jì)模式之責(zé)任鏈模式,簡單說明了責(zé)任鏈模式的概念、原理,并結(jié)合實(shí)例形式分析了java實(shí)現(xiàn)責(zé)任鏈模式的具體用法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08

