Opencsv
上次修改时间:2024 年 7 月 4 日
在本文中,我们将展示如何使用 Opencsv 库,该库用于在 Java 中读取和写入 CSV 文件。我们提供了几个代码示例,用于在 Java 中使用 CSV。
CSV(逗号分隔值)格式是电子表格和数据库中使用的非常流行的数据导入和导出格式。
CSV 文件中的每一行都是一个数据记录。每个记录由一个或多个字段组成,字段之间用逗号分隔。尽管 CSV 格式非常简单,但可能存在许多差异,例如不同的分隔符、换行符或引用字符。
Opencsv 库
Opencsv 是一个非常简单的 Java CSV 解析器库。 它的开发是因为缺乏商业友好的许可证。
<dependencies>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.9</version>
</dependency>
</dependencies>
这是 Opencsv 的 Maven 依赖项。
读取数据
以下示例从 CSV 文件中读取数字。
3,5,6,2,1,7,8 4,5,7,3,2,8,9
我们在 numbers.csv 文件中有两条数据记录。
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
void main() throws IOException, CsvValidationException {
var fileName = "src/main/resources/numbers.csv";
try (var fr = new FileReader(fileName, StandardCharsets.UTF_8);
var reader = new CSVReader(fr)) {
String[] nextLine;
while ((nextLine = reader.readNext()) != null) {
for (var e : nextLine) {
System.out.format("%s ", e);
}
}
}
}
该示例从 numbers.csv 文件中读取数字并将它们打印到控制台。
var fileName = "src/main/resources/numbers.csv";
该文件位于 src/main/resources 目录中。
try (var fr = new FileReader(fileName, StandardCharsets.UTF_8);
var reader = new CSVReader(fr)) {
CSVReader 是用于读取 CSV 文件的类。
while ((nextLine = reader.readNext()) != null) {
for (String e: nextLine) {
System.out.format("%s ", e);
}
}
我们迭代读取器并将值打印到终端。 readNext 方法从缓冲区读取下一行并将其转换为字符串数组。
使用不同的分隔符读取
尽管名称如此,CSV 文件可以使用逗号以外的分隔符分隔。 以下示例展示了如何读取由管道符 | 分隔的数字。
1|2|3|4|5 6|7|3|9|8 9|1|1|0|2
我们有三行数字,用 | 字符分隔。
import com.opencsv.CSVParser;
import com.opencsv.CSVParserBuilder;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
void main() throws IOException, CsvException {
var fileName = "src/main/resources/numbers.csv";
Path myPath = Paths.get(fileName);
CSVParser parser = new CSVParserBuilder().withSeparator('|').build();
try (var br = Files.newBufferedReader(myPath, StandardCharsets.UTF_8);
var reader = new CSVReaderBuilder(br).withCSVParser(parser)
.build()) {
List<String[]> rows = reader.readAll();
for (String[] row : rows) {
for (String e : row) {
System.out.format("%s ", e);
}
System.out.println();
}
}
}
该示例从 numbers.csv 文件中读取值并将它们打印到控制台。
CSVParser parser = new CSVParserBuilder().withSeparator('|').build();
创建了一个带有特定解析器字符的 CSVParser。
try (var br = Files.newBufferedReader(myPath, StandardCharsets.UTF_8);
var reader = new CSVReaderBuilder(br).withCSVParser(parser)
.build()) {
使用 CSVReaderBuilder 创建了一个 CSVReader。
List<String[]> rows = reader.readAll();
我们使用 readAll 方法一次性将所有元素读入一个列表。 此方法不应用于大型文件。
写入数据
CSVWriter 类用于将数据写入 CSV 文件。
import com.opencsv.CSVWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
void main() throws IOException {
String[] entries = { "book", "coin", "pencil", "cup" };
String fileName = "src/main/resources/items.csv";
try (var fos = new FileOutputStream(fileName);
var osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
var writer = new CSVWriter(osw)) {
writer.writeNext(entries);
}
}
该示例将数组中的数据写入 items.csv 文件。 该文件被写入项目根目录。 writeNext 方法将元素数组写入文件。
在下一个代码示例中,我们一次性写入所有数据。
import com.opencsv.CSVWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
void main() throws IOException {
String[] items1 = {"book", "coin", "pencil"};
String[] items2 = {"pen", "chair", "lamp"};
String[] items3 = {"ball", "bowl", "spectacles"};
List<String[]> entries = new ArrayList<>();
entries.add(items1);
entries.add(items2);
entries.add(items3);
String fileName = "src/main/resources/items.csv";
try (var fos = new FileOutputStream(fileName);
var osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
var writer = new CSVWriter(osw)) {
writer.writeAll(entries);
}
}
该示例使用 writeAll 方法将数组列表写入 items.csv 文件。
SQL 数据到 CSV 文件
以下示例从数据库表中检索数据并将其写入 CSV 文件。 我们使用 PostgreSQL 数据库。
除了 opencsv 工件之外,我们还需要 postgresql 驱动程序工件。
-- SQL for the cars table
CREATE TABLE cars(id serial PRIMARY KEY, name VARCHAR(255), price INT);
INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);
这是我们从中检索数据的 Cars 表。
import com.opencsv.CSVWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
void main() {
String url = "jdbc:postgresql://:5432/testdb";
String user = "postgres";
String password = "s$cret";
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
try (var con = DriverManager.getConnection(url, user, password);
var pst = con.prepareStatement("SELECT * FROM cars");
var rs = pst.executeQuery()) {
try (var writer = new CSVWriter(Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8), CSVWriter.DEFAULT_SEPARATOR,
CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END)) {
writer.writeAll(rs, true);
}
} catch (SQLException | IOException ex) {
Logger.getLogger(getClass().getName()).log(
Level.SEVERE, ex.getMessage(), ex);
}
}
在该示例中,我们连接到 PostgreSQL 数据库并从 Cars 表中检索所有行。 数据被写入 cars.csv 文件。
try (var con = DriverManager.getConnection(url, user, password);
var pst = con.prepareStatement("SELECT * FROM cars");
var rs = pst.executeQuery()) {
我们使用驱动程序管理器连接到数据库表并执行 SELECT * FROM cars 语句。
try (var writer = new CSVWriter(Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8), CSVWriter.DEFAULT_SEPARATOR,
CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END)) {
writer.writeAll(rs, true);
}
我们创建一个 CSVWriter,其中包含默认分隔符、无引用字符、无转义字符和默认行尾。
writer.writeAll(rs, true);
writeAll 方法将 java.sql.ResultSet 作为参数。 第二个参数指定是否应包含字段标头。
Opencsv 映射到 JavaBeans
CsvToBean 用于将 CSV 数据映射到 JavaBeans。
按列名映射
使用 HeaderColumnNameMappingStrategy,我们可以使用 CSV 文件第一行中的列名将 CSV 数据映射到 Java 对象
id,name,price 1,Audi,52642 2,Mercedes,57127 3,Skoda,9000 4,Volvo,29000 5,Bentley,350000 6,Citroen,21000 7,Hummer,41400 8,Volkswagen,21600 9,Toyota,26700
这是 cars.csv 文件。 第一条记录包含列名。
import com.opencsv.bean.CsvBindByName;
public class Car {
@CsvBindByName
private int id;
@CsvBindByName
private String name;
@CsvBindByName
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
var builder = new StringBuilder();
builder.append("Car{id=").append(id).append(", name=")
.append(name).append(", price=").append(price).append("}");
return builder.toString();
}
}
Car 是一个 JavaBean。 它包含 @CsvBindByName 注释,用于将 bean 属性映射到 CSV 列。
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
void main() throws IOException {
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(myPath,
StandardCharsets.UTF_8)) {
HeaderColumnNameMappingStrategy<Car> strategy
= new HeaderColumnNameMappingStrategy<>()>
strategy.setType(Car.class);
CsvToBean<Car> csvToBean = new CsvToBeanBuilder<Car>(br)
.withMappingStrategy(strategy)
.withIgnoreLeadingWhiteSpace(true)
.build();
List<Car> cars = csvToBean.parse();
cars.forEach(System.out::println);
}
}
该示例从 cars.csv 文件中读取数据并将它们映射到 Car 对象。 它使用 HeaderColumnNameMappingStrategy。
HeaderColumnNameMappingStrategy<Car> strategy
= new HeaderColumnNameMappingStrategy<>();
strategy.setType(Car.class);
HeaderColumnNameMappingStrategy 使用 CSV 文件第一行中的列名将数据映射到对象。 列顺序无关紧要。
CsvToBean<Car> csvToBean = new CsvToBeanBuilder<Car>(br)
.withMappingStrategy(strategy)
.withIgnoreLeadingWhiteSpace(true)
.build();
使用 CsvToBeanBuilder 创建一个 CsvToBean。 我们指定映射策略。
List<Car> cars = csvToBean.parse();
使用 CsvToBean 的 parse 方法,我们将 CSV 数据解析为列表。
cars.forEach(System.out::println);
我们遍历 bean 列表并将它们打印到控制台。
按列位置映射
ColumnPositionMappingStrategy 按其位置映射列。
1,Audi,52642 2,Mercedes,57127 3,Skoda,9000 4,Volvo,29000 5,Bentley,350000 6,Citroen,21000 7,Hummer,41400 8,Volkswagen,21600 9,Toyota,26700
这是 cars.csv 文件。
import com.opencsv.bean.CsvBindByPosition;
public class Car {
@CsvBindByPosition(position = 0)
private int id;
@CsvBindByPosition(position = 1)
private String name;
@CsvBindByPosition(position = 2)
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
var builder = new StringBuilder();
builder.append("Car{id=").append(id).append(", name=")
.append(name).append(", price=").append(price).append("}");
return builder.toString();
}
}
@CsvBindByPosition 指定 CSV 输入的列号和 bean 中的字段之间的绑定。
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
void main() throws IOException {
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(myPath,
StandardCharsets.UTF_8)) {
ColumnPositionMappingStrategy<Car> strategy = new ColumnPositionMappingStrategy<>();
strategy.setType(Car.class);
String[] fields = {"id", "name", "price"};
strategy.setColumnMapping(fields);
CsvToBean<Car> csvToBean = new CsvToBeanBuilder<Car>(br)
.withMappingStrategy(strategy)
.withIgnoreLeadingWhiteSpace(true)
.build();
List<Car> cars = csvToBean.parse();
cars.forEach(System.out::println);
}
}
该示例从 cars.csv 文件中读取数据并将它们映射到 Car 对象。 它使用 ColumnPositionMappingStrategy。
ColumnPositionMappingStrategy<Car> strategy = new ColumnPositionMappingStrategy<>();
strategy.setType(Car.class);
String[] fields = {"id", "name", "price"};
strategy.setColumnMapping(fields);
我们创建一个 ColumnPositionMappingStrategy。 使用 setColumnMapping 我们设置要映射的列名。
Opencsv 使用 StatefulBeanToCsv 写入 JavaBeans
在下一个示例中,我们使用 StatefulBeanToCsv 将 JavaBeans 写入 CSV。
public class Car {
private int id;
private String name;
private int price;
public Car() {
}
public Car(int id, String name, int price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
var builder = new StringBuilder();
builder.append("Car{id=").append(id).append(", name=")
.append(name).append(", price=").append(price).append("}");
return builder.toString();
}
}
这是一个 Car bean。
import com.opencsv.CSVWriter;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
void main() {
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
var cars = List.of(new Car(1, "Audi", 52642),
new Car(2, "Mercedes", 57127),
new Car(3, "Skoda", 9000),
new Car(4, "Volvo", 29000));
try (var writer = Files.newBufferedWriter(myPath, StandardCharsets.UTF_8)) {
StatefulBeanToCsv<Car> beanToCsv = new StatefulBeanToCsvBuilder<Car>(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.build();
beanToCsv.write(cars);
} catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException |
IOException ex) {
Logger.getLogger(getClass().getName()).log(
Level.SEVERE, ex.getMessage(), ex);
}
}
该示例创建一个汽车对象列表并将它们写入 CSV 文件。
var cars = List.of(new Car(1, "Audi", 52642),
new Car(2, "Mercedes", 57127),
new Car(3, "Skoda", 9000),
new Car(4, "Volvo", 29000));
我们创建一个汽车对象列表。
StatefulBeanToCsv<Car> beanToCsv = new StatefulBeanToCsvBuilder<Car>(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.build();
使用 StatefulBeanToCsvBuilder 创建一个 StatefulBeanToCsv。
beanToCsv.write(cars);
bean 被写入文件。
在本文中,我们使用了 Opencsv 库。 我们从 CSV 文件中读取了数据,将数据写入 CSV 文件,将数据从数据库表导出到 CSV 文件,并将 CSV 数据映射到 bean。
来源
作者
列出所有Java教程。