1. 简介
在本快速教程中,我们将介绍OpenCSV 4,这是一个用于编写、读取、序列化、反序列化和/或解析.csv文件的出色库。然后,我们将通过几个示例演示如何设置和使用OpenCSV 4来完成我们的工作。
2. 设置
首先,我们将通过pom.xml依赖将OpenCSV添加到我们的项目中:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.9</version>
</dependency>
你可以在官方网站或通过Maven仓库快速搜索找到OpenCSV的.jar。
我们的.csv文件非常简单;我们将其保留为两列四行:
colA,colB
A,B
C,D
G,G
G,F
3. Bean或者非Bean
将OpenCSV添加到pom.xml后,我们可以通过两种方便的方式实现CSV处理方法:
- 使用方便的CSVReader和CSVWriter对象(用于更简单的操作)
- 使用CsvToBean将.csv文件转换为Bean(以带注解的POJO形式实现)
在本文中,我们将坚持使用同步(或阻塞)示例,以便我们能够专注于基础知识。
请记住,同步方法将阻塞周围或后续代码的执行,直到完成为止。生产环境可能会使用异步(或非阻塞)方法,以便在异步方法完成时允许其他进程或方法完成。
我们将在后续文章中深入探讨OpenCSV的异步示例。
3.1 CSVReader
让我们通过提供的readAll()和readNext()方法探索CSVReader,我们将了解如何同步使用readAll():
public List<String[]> readAllLines(Path filePath) throws Exception {
try (Reader reader = Files.newBufferedReader(filePath)) {
try (CSVReader csvReader = new CSVReader(reader)) {
return csvReader.readAll();
}
}
}
然后我们可以通过传入文件路径来调用该方法:
public List<String[]> readAllLinesExample() throws Exception {
Path path = Paths.get(
ClassLoader.getSystemResource("csv/twoColumn.csv").toURI())
);
return CsvReaderExamples.readAllLines(path);
}
类似地,我们可以抽象出readNext(),它逐行读取提供的.csv:
public List<String[]> readLineByLine(Path filePath) throws Exception {
List<String[]> list = new ArrayList<>();
try (Reader reader = Files.newBufferedReader(filePath)) {
try (CSVReader csvReader = new CSVReader(reader)) {
String[] line;
while ((line = csvReader.readNext()) != null) {
list.add(line);
}
}
}
return list;
}
最后,我们可以通过传入文件路径来调用该方法:
public List<String[]> readLineByLineExample() throws Exception {
Path path = Paths.get(
ClassLoader.getSystemResource("csv/twoColumn.csv").toURI())
);
return CsvReaderExamples.readLineByLine(path);
}
或者,为了获得更大的灵活性和配置选项,我们可以使用CSVReaderBuilder:
CSVParser parser = new CSVParserBuilder()
.withSeparator(',')
.withIgnoreQuotations(true)
.build();
CSVReader csvReader = new CSVReaderBuilder(reader)
.withSkipLines(0)
.withCSVParser(parser)
.build();
CSVReaderBuilder允许我们跳过列标题并通过CSVParserBuilder设置解析规则。
使用CSVParserBuilder,我们可以选择自定义列分隔符,忽略或处理引号,说明如何处理空字段以及如何解释转义字符。有关这些配置设置的更多信息,请参阅官方规范文档。
与往常一样,我们需要记得关闭所有读取器以防止内存泄漏。
3.2 CSVWriter
CSVWriter类似地提供一次性或逐行写入.csv文件的功能。
让我们看看如何逐行写入.csv:
public String writeLineByLine(List<String[]> lines, Path path) throws Exception {
try (CSVWriter writer = new CSVWriter(new FileWriter(path.toString()))) {
for (String[] line : lines) {
writer.writeNext(line);
}
return Helpers.readFile(path);
}
}
然后我们指定要保存文件的位置,并调用刚刚编写的方法:
public String writeLineByLineExample() throws Exception {
Path path = Paths.get(
ClassLoader.getSystemResource("csv/writtenOneByOne.csv").toURI()
);
return CsvWriterExamples.writeLineByLine(Helpers.fourColumnCsvString(), path);
}
我们还可以通过传入代表.csv行的字符串数组列表来一次性写入.csv:
public String writeAllLines(List<String[]> lines, Path path) throws Exception {
try (CSVWriter writer = new CSVWriter(new FileWriter(path.toString()))) {
writer.writeAll(stringArray);
}
return Helpers.readFile(path);
}
最后,我们这样调用它:
public String writeAllLinesExample() throws Exception {
Path path = Paths.get(
ClassLoader.getSystemResource("csv/writtenAll.csv").toURI()
);
return CsvWriterExamples.writeAllLines(Helpers.fourColumnCsvString(), path);
}
3.3 基于Bean的读取
OpenCSV能够将.csv文件序列化为预设的可重用模式,并以带注解的Java POJO Bean形式实现。CsvToBean是使用CsvToBeanBuilder构建的,从OpenCSV 4开始,CsvToBeanBuilder是使用com.opencsv.bean.CsvToBean的推荐方式。
这是一个简单的Bean,我们可以使用它来序列化我们之前的两列.csv:
public class SimplePositionBean {
@CsvBindByPosition(position = 0)
private String exampleColOne;
@CsvBindByPosition(position = 1)
private String exampleColTwo;
// getters and setters
}
.csv文件中的每一列都与Bean中的一个字段相关联,我们可以使用@CsvBindByPosition或@CsvBindByName注解执行.csv列标题之间的映射,它们分别通过位置或标头字符串匹配指定映射。
首先,我们将创建一个名为CsvBean的超类,它将允许我们重用和概括下面构建的方法:
public class CsvBean { }
这是一个子类的示例:
public class NamedColumnBean extends CsvBean {
@CsvBindByName(column = "name")
private String name;
// Automatically infer column name as 'Age'
@CsvBindByName
private int age;
// getters and setters
}
接下来,我们将使用CsvToBean抽象一个同步返回的列表:
public List<CsvBean> beanBuilderExample(Path path, Class clazz) throws Exception {
CsvTransfer csvTransfer = new CsvTransfer();
try (Reader reader = Files.newBufferedReader(path)) {
CsvToBean<CsvBean> cb = new CsvToBeanBuilder<CsvBean>(reader)
.withType(clazz)
.build();
csvTransfer.setCsvList(cb.parse());
}
return csvTransfer.getCsvList();
}
然后传入我们的Bean(clazz),这样做是为了将Bean的字段与.csv行的相应列关联起来。
我们可以在这里使用上面编写的CsvBean的SimplePositionBean子类来调用它:
public List<CsvBean> simplePositionBeanExample() throws Exception {
Path path = Paths.get(ClassLoader.getSystemResource("csv/twoColumn.csv").toURI());
return BeanExamples.beanBuilderExample(path, SimplePositionBean.class);
}
我们也可以在这里使用CsvBean的另一个子类NamedColumnBean来调用它:
public List<CsvBean> namedColumnBeanExample() throws Exception {
Path path = Paths.get(ClassLoader.getSystemResource("csv/namedColumn.csv").toURI());
return BeanExamples.beanBuilderExample(path, NamedColumnBean.class);
}
3.4 基于Bean的写入
最后我们来看看如何使用StatefulBeanToCsv类写入.csv文件:
public String writeCsvFromBean(Path path) throws Exception {
List<CsvBean> sampleData = Arrays.asList(
new WriteExampleBean("Test1", "sfdsf", "fdfd"),
new WriteExampleBean("Test2", "ipso", "facto")
);
try (Writer writer = new FileWriter(path.toString())) {
StatefulBeanToCsv<CsvBean> sbc = new StatefulBeanToCsvBuilder<CsvBean>(writer)
.withQuotechar('\'')
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.build();
sbc.write(sampleData);
}
return Helpers.readFile(path);
}
这里我们指定如何界定和引用我们的数据,它以指定CsvBean对象的列表的形式提供。
然后,我们可以传递所需的输出文件路径后调用方法writeCsvFromBean():
public String writeCsvFromBeanExample() {
Path path = Paths.get(ClassLoader.getSystemResource("csv/writtenBean.csv").toURI());
return BeanExamples.writeCsvFromBean(path);
}
4. 总结
在这篇简短的文章中,我们讨论了使用Bean、CSVReader和CSVWriter的OpenCSV同步代码示例。有关更多信息,请查看此处的官方文档。
Post Directory
