原文:http://zetcode.com/articles/opencsv/
在 Opencsv 教程中,我们展示了如何与 Opencsv 库一起使用,该库用于在 Java 中读写 CSV 文件。 我们提供了一些代码示例,可在 Java 中使用 CSV。 该教程的源代码也可以从作者的 Github 仓库中获得。
CSV(逗号分隔值)格式是在电子表格和数据库中使用的非常流行的导入和导出格式。
CSV 文件中的每一行都是一个数据记录。 每个记录由一个或多个字段组成,用逗号分隔。 尽管 CSV 格式是一种非常简单的格式,但还是有许多差异,例如不同的定界符,换行或引号字符。
Opencsv 库
Opencsv 是一个非常简单的 Java CSV 解析器库。 它的开发是由于缺乏商业友好许可证。
<dependencies><dependency><groupId>com.opencsv</groupId><artifactId>opencsv</artifactId><version>4.1</version></dependency></dependencies>
这是 Opencsv 的 Maven 依赖关系。
OpenCSV 读取数据
以下示例从 CSV 文件读取数字。
$ tree.├── nbactions.xml├── pom.xml└── src├── main│ ├── java│ │ └── com│ │ └── zetcode│ │ └── OpenCSVReadEx.java│ └── resources│ └── numbers.csv└── test└── java
这是项目结构。
numbers.csv
3,5,6,2,1,7,84,5,7,3,2,8,9
numbers.csv文件中有两个数据记录。
OpenCSVReadEx.java
package com.zetcode;import com.opencsv.CSVReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.nio.charset.StandardCharsets;public class OpenCSVReadEx {public static void main(String[] args) throws IOException {String fileName = "src/main/resources/numbers.csv";try (FileInputStream fis = new FileInputStream(fileName);InputStreamReader isr = new InputStreamReader(fis,StandardCharsets.UTF_8);CSVReader reader = new CSVReader(isr)) {String[] nextLine;while ((nextLine = reader.readNext()) != null) {for (String e : nextLine) {System.out.format("%s ", e);}}}}}
该示例从numbers.csv文件中读取数字并将其打印到控制台。
String fileName = "src/main/resources/numbers.csv";
该文件位于src/main/resources目录中。
try (FileInputStream fis = new FileInputStream(fileName);InputStreamReader isr = new InputStreamReader(fis,StandardCharsets.UTF_8);CSVReader reader = new CSVReader(isr)) {
CSVReader是用于读取 CSV 文件的类。
while ((nextLine = reader.readNext()) != null) {for (String e: nextLine) {System.out.format("%s ", e);}}
我们遍历读取器并将值打印到终端。 readNext()方法从缓冲区读取下一行,并转换为字符串数组。
3 5 6 2 1 7 8 4 5 7 3 2 8 9
这是程序的输出。
使用不同的分隔符的 OpenCSV 读取
尽管有 CSV 文件的名称,但也可以用逗号以外的分隔符分隔 CSV 文件。 下面的示例显示如何读取由竖线分隔的数字字符。
此示例使用 Gradle 工具构建。
$ tree.├── build.gradle├── settings.gradle└── src├── main│ ├── java│ │ └── com│ │ └── zetcode│ │ └── OpenCSVReadEx2.java│ └── resources│ └── numbers.csv└── test├── java└── resources
我们展示了项目结构。
settings.gradle
rootProject.name = 'OpenCSVReadEx2'
这是 Gradle 设置文件。
build.gradle
apply plugin: 'application'archivesBaseName = "readnumbers2"version = '1.0'mainClassName = "com.zetcode.OpenCSVReadEx2"sourceCompatibility = '1.8'compileJava.options.encoding = 'UTF-8'repositories {mavenCentral()}dependencies {compile group: 'com.opencsv', name: 'opencsv', version: '4.1'}
这是 Gradle 构建文件。
numbers.csv
1|2|3|4|56|7|3|9|89|1|1|0|2
我们有三行数字,中间用|分隔。 字符。
OpenCSVReadEx2.java
package com.zetcode;import com.opencsv.CSVParser;import com.opencsv.CSVParserBuilder;import com.opencsv.CSVReader;import com.opencsv.CSVReaderBuilder;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;public class OpenCSVReadEx2 {public static void main(String[] args) throws IOException {String fileName = "src/main/resources/numbers.csv";Path myPath = Paths.get(fileName);CSVParser parser = new CSVParserBuilder().withSeparator('|').build();try (BufferedReader br = Files.newBufferedReader(myPath,StandardCharsets.UTF_8);CSVReader 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 (BufferedReader br = Files.newBufferedReader(myPath,StandardCharsets.UTF_8);CSVReader reader = new CSVReaderBuilder(br).withCSVParser(parser).build()) {
用CSVReaderBuilder创建一个CSVReader。
List<String[]> rows = reader.readAll();
我们使用readAll()方法将所有元素读入列表中。 此方法不应用于大文件。
$ gradle build$ gradle run:compileJava UP-TO-DATE:processResources UP-TO-DATE:classes UP-TO-DATE:run1 2 3 4 56 7 3 9 89 1 1 0 2
我们构建并运行该示例。
OpenCSV 写入数据
CSVWriter类用于将数据写入 CSV 文件。
OpenCSVWriteEx.java
package com.zetcode;import com.opencsv.CSVWriter;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;import java.nio.charset.StandardCharsets;public class OpenCSVWriteEx {public static void main(String[] args) throws IOException {String[] entries = { "book", "coin", "pencil", "cup" };String fileName = "src/main/resources/items.csv";try (FileOutputStream fos = new FileOutputStream(fileName);OutputStreamWriter osw = new OutputStreamWriter(fos,StandardCharsets.UTF_8);CSVWriter writer = new CSVWriter(osw)) {writer.writeNext(entries);}}}
该示例将数据从数组写入items.csv文件。 该文件将写入项目根目录。 writeNext()方法将元素数组写入文件。
在下一个代码示例中,我们将所有数据一次性写入。
OpenCSVWriteEx2.java
package com.zetcode;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;public class OpenCSVWriteEx2 {public static void main(String[] args) 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 (FileOutputStream fos = new FileOutputStream(fileName);OutputStreamWriter osw = new OutputStreamWriter(fos,StandardCharsets.UTF_8);CSVWriter writer = new CSVWriter(osw)) {writer.writeAll(entries);}}}
该示例使用writeAll()方法将数组列表写入items.csv文件。
将 SQL 数据转换为 CSV 文件
以下示例从数据库表中检索数据并将其写入 CSV 文件。 我们使用 MySQL 数据库。 有关 MySQL 和 MySQL Java 编程的更多信息,请参见 MySQL 教程和 MySQL Java 教程。
cars_mysql.sql
-- SQL for the Cars tableCREATE TABLE Cars(Id BIGINT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(150),Price INTEGER);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表。
pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zetcode</groupId><artifactId>OpenCSVDatabaseEx</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>com.opencsv</groupId><artifactId>opencsv</artifactId><version>4.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.45</version></dependency></dependencies></project>
Maven 构建文件包含 Opencsv 和 MySQL 驱动程序的依赖项。
OpenCSVDatabaseEx.java
package com.zetcode;import com.opencsv.CSVWriter;import java.io.FileWriter;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.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.logging.Level;import java.util.logging.Logger;public class OpenCSVDatabaseEx {public static void main(String[] args) {String url = "jdbc:mysql://localhost:3306/testdb?useSsl=false";String user = "testuser";String password = "test623";String fileName = "src/main/resources/cars.csv";Path myPath = Paths.get(fileName);try (Connection con = DriverManager.getConnection(url, user, password);PreparedStatement pst = con.prepareStatement("SELECT * FROM Cars");ResultSet rs = pst.executeQuery()) {try (CSVWriter 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(OpenCSVDatabaseEx.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);}}}
在示例中,我们连接到 MySQL 数据库并从Cars表中检索所有行。 数据被写入cars.csv文件。
try (Connection con = DriverManager.getConnection(url, user, password);PreparedStatement pst = con.prepareStatement("SELECT * FROM Cars");ResultSet rs = pst.executeQuery()) {
我们使用驱动程序管理器连接到数据库表,并执行SELECT * FROM Cars语句。
try (CSVWriter writer = new CSVWriter(Files.newBufferedWriter(myPath,StandardCharsets.UTF_8), CSVWriter.DEFAULT_SEPARATOR,CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER,CSVWriter.DEFAULT_LINE_END)) {
我们创建一个CSVWriter,它带有默认的分隔符,没有引号,没有转义符和默认行尾。
writer.writeAll(rs, true);
writeAll()方法将java.sql.ResultSet作为参数。 第二个参数指定是否应包含字段头。
$ cat cars.csvID,NAME,PRICE1,Audi,526422,Mercedes,571273,Skoda,90004,Volvo,290005,Bentley,3500006,Citroen,210007,Hummer,414008,Volkswagen,216009,Toyota,26700
代码示例将生成此文件。
Opencsv 映射到 JavaBeans
CsvToBean用于将 CSV 数据映射到 JavaBeans。
按列名映射
使用HeaderColumnNameMappingStrategy,我们可以使用 CSV 文件第一行中的列名将 CSV 数据映射到 Java 对象
$ tree.├── nbactions.xml├── pom.xml└── src├── main│ ├── java│ │ └── com│ │ └── zetcode│ │ ├── bean│ │ │ └── Car.java│ │ └── OpenCSVReadBeansEx.java│ └── resources│ └── cars.csv└── test└── java
This is the project structure.
cars.csv
ID,NAME,PRICE1,Audi,526422,Mercedes,571273,Skoda,90004,Volvo,290005,Bentley,3500006,Citroen,210007,Hummer,414008,Volkswagen,216009,Toyota,26700
这是cars.csv文件。 第一条记录包含列名。
Car.java
package com.zetcode.bean;import com.opencsv.bean.CsvBindByName;public class Car {@CsvBindByNameprivate int id;@CsvBindByNameprivate String name;@CsvBindByNameprivate 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;}@Overridepublic String toString() {StringBuilder 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 列。
OpenCSVReadBeansEx.java
package com.zetcode;import com.opencsv.bean.CsvToBean;import com.opencsv.bean.CsvToBeanBuilder;import com.opencsv.bean.HeaderColumnNameMappingStrategy;import com.zetcode.bean.Car;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;public class OpenCSVReadBeansEx {public static void main(String[] args) 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 csvToBean = new CsvToBeanBuilder(br).withType(Car.class).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 csvToBean = new CsvToBeanBuilder(br).withType(Car.class).withMappingStrategy(strategy).withIgnoreLeadingWhiteSpace(true).build();
用CsvToBeanBuilder创建一个CsvToBean。 我们指定类型和映射策略。
List<Car> cars = csvToBean.parse();
使用CsvToBean的parse()方法,我们将 CSV 数据解析到列表中。
cars.forEach(System.out::println);
我们遍历 bean 列表并将它们打印到控制台。
Car{id=1, name=Audi, price=52642}Car{id=2, name=Mercedes, price=57127}Car{id=3, name=Skoda, price=9000}Car{id=4, name=Volvo, price=29000}Car{id=5, name=Bentley, price=350000}Car{id=6, name=Citroen, price=21000}Car{id=7, name=Hummer, price=41400}Car{id=8, name=Volkswagen, price=21600}Car{id=9, name=Toyota, price=26700}
这是示例的输出。
按列位置进行映射
ColumnPositionMappingStrategy按列的位置映射。
cars.csv
1,Audi,526422,Mercedes,571273,Skoda,90004,Volvo,290005,Bentley,3500006,Citroen,210007,Hummer,414008,Volkswagen,216009,Toyota,26700
这是cars.csv文件。
Car.java
package com.zetcode.bean;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;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("Car{id=").append(id).append(", name=").append(name).append(", price=").append(price).append("}");return builder.toString();}}
@CsvBindByPosition指定 CSV 输入的列号和 bean 中的字段之间的绑定。
OpenCSVReadBeansEx2.java
package com.zetcode;import com.opencsv.bean.ColumnPositionMappingStrategy;import com.opencsv.bean.CsvToBean;import com.opencsv.bean.CsvToBeanBuilder;import com.zetcode.bean.Car;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;public class OpenCSVReadBeansEx2 {public static void main(String[] args) throws IOException {String fileName = "src/main/resources/cars.csv";Path myPath = Paths.get(fileName);try (BufferedReader br = Files.newBufferedReader(myPath,StandardCharsets.UTF_8)) {ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();strategy.setType(Car.class);String[] fields = {"id", "name", "price"};strategy.setColumnMapping(fields);CsvToBean csvToBean = new CsvToBeanBuilder(br).withType(Car.class).withMappingStrategy(strategy).withIgnoreLeadingWhiteSpace(true).build();List<Car> cars = csvToBean.parse();cars.forEach(System.out::println);}}}
该示例从cars.csv文件中读取数据,并将它们映射到Car对象。 它使用ColumnPositionMappingStrategy。
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();strategy.setType(Car.class);String[] fields = {"id", "name", "price"};strategy.setColumnMapping(fields);
我们创建一个ColumnPositionMappingStrategy。 使用setColumnMapping(),我们设置要映射的列名。
Opencsv 使用StatefulBeanToCsv编写 JavaBeans
在下一个示例中,我们使用StatefulBeanToCsv将 JavaBeans 写入 CSV。
Car.java
package com.zetcode.bean;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;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("Car{id=").append(id).append(", name=").append(name).append(", price=").append(price).append("}");return builder.toString();}}
这是一个Car bean。
OpenCSVWriteBeansEx.java
package com.zetcode;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 com.zetcode.bean.Car;import java.io.BufferedWriter;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.ArrayList;import java.util.List;import java.util.logging.Level;import java.util.logging.Logger;public class OpenCSVWriteBeansEx {public static void main(String[] args) {String fileName = "src/main/resources/cars.csv";Path myPath = Paths.get(fileName);List<Car> cars = new ArrayList<>();cars.add(new Car(1, "Audi", 52642));cars.add(new Car(2, "Mercedes", 57127));cars.add(new Car(3, "Skoda", 9000));cars.add(new Car(4, "Volvo", 29000));try (BufferedWriter writer = Files.newBufferedWriter(myPath,StandardCharsets.UTF_8)) {StatefulBeanToCsv<Car> beanToCsv = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).build();beanToCsv.write(cars);} catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException |IOException ex) {Logger.getLogger(OpenCSVWriteBeansEx.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);}}}
该示例创建一个汽车对象列表,并将其写入 CSV 文件。
List<Car> cars = new ArrayList<>();cars.add(new Car(1, "Audi", 52642));cars.add(new Car(2, "Mercedes", 57127));cars.add(new Car(3, "Skoda", 9000));cars.add(new Car(4, "Volvo", 29000));
我们创建汽车对象列表。
StatefulBeanToCsv<Car> beanToCsv = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).build();
用StatefulBeanToCsvBuilder创建一个StatefulBeanToCsv。
beanToCsv.write(cars);
Bean 被写入文件。
在本教程中,我们使用了 Opencsv 库。 我们已经从 CSV 文件读取数据,将数据写入 CSV 文件,从数据库表中导出数据到 CSV 文件,以及将 CSV 数据映射到 bean。
您可能也对以下相关教程感兴趣: Java 教程,读取 WAR 中的 CSV 文件,Java 文本文件读取 和 jQuery 自动完成教程。
