在之前的一篇文章中,我写了如何使用 Apache Commons CSV 在 Java 中读取和写入 CSV 文件。
在本文中,我将带您了解另一个名为 OpenCSV 的开源库,用于在 Java 中读写 CSV 文件。
首先,您需要在您的项目中添加 OpenCSV 依赖项。如果您是 Maven 用户,请将以下依赖项添加到您的 pom.xml
文件中。
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.0</version>
</dependency>
这是 Gradle 的依赖项 -
compile "com.opencsv:opencsv:4.0"
以下是我们将在本文提供的示例中读取和解析的两个示例 CSV 文件。
没有标题的 CSV 文件 - users.csv
Rajeev Kumar Singh ♥,rajeevs@example.com,+91-9999999999,India
Sachin Tendulkar,sachin@example.com,+91-9999999998,India
Barak Obama,barak.obama@example.com,+1-1111111111,United States
Donald Trump,donald.trump@example.com,+1-2222222222,United States
带有标题的 CSV 文件 - users-with-header.csv
name,email,phone,country
Rajeev Kumar Singh ♥,rajeevs@example.com,+91-9999999999,India
Sachin Tendulkar,sachin@example.com,+91-9999999998,India
Barak Obama,barak.obama@example.com,+1-1111111111,United States
Donald Trump,donald.trump@example.com,+1-2222222222,United States
下面的示例展示了如何使用 OpenCSV 库读取和解析 CSV 文件。它将 CSV 记录一一读入字符串数组中 -
import com.opencsv.CSVReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
public class OpenCSVReader {
private static final String SAMPLE_CSV_FILE_PATH = "./users.csv";
public static void main(String[] args) throws IOException {
try (
Reader reader = Files.newBufferedReader(Paths.get(SAMPLE_CSV_FILE_PATH));
CSVReader csvReader = new CSVReader(reader);
) {
// Reading Records One by One in a String array
String[] nextRecord;
while ((nextRecord = csvReader.readNext()) != null) {
System.out.println("Name : " + nextRecord[0]);
System.out.println("Email : " + nextRecord[1]);
System.out.println("Phone : " + nextRecord[2]);
System.out.println("Country : " + nextRecord[3]);
System.out.println("==========================");
}
}
}
}
#####一次读取所有记录
在上面的例子中,我们使用 readNext()
方法一一读取 CSV 记录。 CSVReader
还提供了一个名为 readAll()
的方法,可以一次性将所有记录读入 List<String[]>
。
// Reading All Records at once into a List<String[]>
List<String[]> records = csvReader.readAll();
for (String[] record : records) {
System.out.println("Name : " + record[0]);
System.out.println("Email : " + record[1]);
System.out.println("Phone : " + record[2]);
System.out.println("Country : " + record[3]);
System.out.println("---------------------------");
}
请注意,上述方法将整个 CSV 内容加载到内存中,因此不适用于大型 CSV 文件。
如果您尝试读取包含标题的示例 CSV 文件,则标题记录也将打印在输出中。如果要跳过标题行,则可以使用 CSVReaderBuilder
类构造一个 CSVReader
并跳过指定的行数。
import com.opencsv.CSVReaderBuilder;
CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build();
OpenCSV 库的真正优势在于您可以直接将 CSV 记录解析为 Java 对象。有两种方法可以做到——第一种方法使用注释,第二种方法使用映射策略。
OpenCSV 中有两种类型的注释 - @CsvBindByName
和 @CsvBindByPosition
。您可以使用这些注释来指定应将哪个 CSV 列绑定到 Java 对象的哪个成员字段。
如果 CSV 文件包含标题,则可以使用 @CsvBindByName
批注指定 CSV 列和成员字段之间的映射。
@CsvBindByName
注释接受三个参数 - column、required 和 locale。 required
和 locale
参数是可选的,如果 CSV 文件中的标题名称与成员字段名称相同,您也可以省略 column
参数。
这是一个使用 @CsvBindByName
注释的 POJO 类的示例 -
import com.opencsv.bean.CsvBindByName;
public class CSVUser {
@CsvBindByName
private String name;
@CsvBindByName(column = "email", required = true)
private String email;
@CsvBindByName(column = "phone")
private String phoneNo;
@CsvBindByName
private String country;
// Getters and Setters (Omitted for brevity)
}
下面的示例显示了如何将 CSV 记录直接读取和解析为 Java 对象 -
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;
public class OpenCSVReadAndParseToBean {
private static final String SAMPLE_CSV_FILE_PATH = "./users-with-header.csv";
public static void main(String[] args) throws IOException {
try (
Reader reader = Files.newBufferedReader(Paths.get(SAMPLE_CSV_FILE_PATH));
) {
CsvToBean<CSVUser> csvToBean = new CsvToBeanBuilder(reader)
.withType(CSVUser.class)
.withIgnoreLeadingWhiteSpace(true)
.build();
Iterator<CSVUser> csvUserIterator = csvToBean.iterator();
while (csvUserIterator.hasNext()) {
CSVUser csvUser = csvUserIterator.next();
System.out.println("Name : " + csvUser.getName());
System.out.println("Email : " + csvUser.getEmail());
System.out.println("PhoneNo : " + csvUser.getPhoneNo());
System.out.println("Country : " + csvUser.getCountry());
System.out.println("==========================");
}
}
}
}
在上面的例子中,我们从 csvToBean
对象中获取了一个 Iterator
,然后循环遍历这个迭代器,将每个对象一一检索。
CsvToBean
类还提供了一个 parse()
方法,该方法解析整个 CSV 文件并将所有对象一次加载到内存中。你可以像这样使用它 -
// Reads all CSV contents into memory (Not suitable for large CSV files)
List<CSVUser> csvUsers = csvToBean.parse();
for(CSVUser csvUser: csvUsers) {
System.out.println("Name : " + csvUser.getName());
System.out.println("Email : " + csvUser.getEmail());
System.out.println("PhoneNo : " + csvUser.getPhoneNo());
System.out.println("Country : " + csvUser.getCountry());
System.out.println("==========================");
}
显然,上述方法不适合非常大的 CSV 文件,因为它将整个 CSV 文件内容加载到内存中。
如果您的 CSV 文件不包含标题,那么您可以使用 @CsvBindByPosition
注释来指定这样的映射 -
import com.opencsv.bean.CsvBindByPosition;
public class CSVUser {
@CsvBindByPosition(position = 0)
private String name;
@CsvBindByPosition(position = 1)
private String email;
@CsvBindByPosition(position = 2)
private String phoneNo;
@CsvBindByPosition(position = 3)
private String country;
// Getters and Setters (Omitted for brevity)
}
如果您不想用 OpenCSV 注释使 POJO 类混乱,那么您可以使用 Mapping 策略来指定 CSV 列和对象成员字段之间的映射。
考虑以下 MyUser
类。
public class MyUser {
private String name;
private String email;
private String phoneNo;
private String country;
public MyUser() {
}
public MyUser(String name, String email, String phoneNo, String country) {
this.name = name;
this.email = email;
this.phoneNo = phoneNo;
this.country = country;
}
// Getters and Setters (Omitted for brevity)
}
以下是如何使用 ColumnPositionMappingStrategy
指定 CSV 列和 Java 对象的成员字段之间的映射,并将 CSV 记录解析为 Java 对象。
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;
public class OpenCSVParseToBeanWithoutAnnotation {
private static final String SAMPLE_CSV_FILE_PATH = "./users-with-header.csv";
public static void main(String[] args) throws IOException {
try (
Reader reader = Files.newBufferedReader(Paths.get(SAMPLE_CSV_FILE_PATH));
) {
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();
strategy.setType(MyUser.class);
String[] memberFieldsToBindTo = {"name", "email", "phoneNo", "country"};
strategy.setColumnMapping(memberFieldsToBindTo);
CsvToBean<MyUser> csvToBean = new CsvToBeanBuilder(reader)
.withMappingStrategy(strategy)
.withSkipLines(1)
.withIgnoreLeadingWhiteSpace(true)
.build();
Iterator<MyUser> myUserIterator = csvToBean.iterator();
while (myUserIterator.hasNext()) {
MyUser myUser = myUserIterator.next();
System.out.println("Name : " + myUser.getName());
System.out.println("Email : " + myUser.getEmail());
System.out.println("PhoneNo : " + myUser.getPhoneNo());
System.out.println("Country : " + myUser.getCountry());
System.out.println("---------------------------");
}
}
}
}
ColumnPositionMappingStrategy
用于声明基于位置的映射。在上面的例子中,我们将第一列绑定到 name
字段,第二列绑定到 email
字段等等......
您可以从字符串数组或对象列表生成 CSV 文件。
下面的示例显示了如何通过将字符串数组写入 CSV 文件的每一行来生成 CSV 文件。
import com.opencsv.CSVWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
public class OpenCSVWriter {
private static final String STRING_ARRAY_SAMPLE = "./string-array-sample.csv";
public static void main(String[] args) throws IOException {
try (
Writer writer = Files.newBufferedWriter(Paths.get(STRING_ARRAY_SAMPLE));
CSVWriter csvWriter = new CSVWriter(writer,
CSVWriter.DEFAULT_SEPARATOR,
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END);
) {
String[] headerRecord = {"Name", "Email", "Phone", "Country"};
csvWriter.writeNext(headerRecord);
csvWriter.writeNext(new String[]{"Sundar Pichai ♥", "sundar.pichai@gmail.com", "+1-1111111111", "India"});
csvWriter.writeNext(new String[]{"Satya Nadella", "satya.nadella@outlook.com", "+1-1111111112", "India"});
}
}
}
最后,以下示例展示了如何从对象列表生成 CSV 文件。该示例使用上一节中定义的 MyUser
类 -
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.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class OpenCSVWriter {
private static final String OBJECT_LIST_SAMPLE = "./object-list-sample.csv";
public static void main(String[] args) throws IOException,
CsvDataTypeMismatchException,
CsvRequiredFieldEmptyException {
try (
Writer writer = Files.newBufferedWriter(Paths.get(STRING_ARRAY_SAMPLE));
) {
StatefulBeanToCsv<MyUser> beanToCsv = new StatefulBeanToCsvBuilder(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.build();
List<MyUser> myUsers = new ArrayList<>();
myUsers.add(new MyUser("Sundar Pichai ♥", "sundar.pichai@gmail.com", "+1-1111111111", "India"));
myUsers.add(new MyUser("Satya Nadella", "satya.nadella@outlook.com", "+1-1111111112", "India"));
beanToCsv.write(myUsers);
}
}
}
这就是所有的人!在本文中,我们研究了使用 OpenCSV 库在 Java 中读取和写入 CSV 文件的不同方法。
您可以在 my github repository 中找到本文中提供的所有代码示例。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.callicoder.com/java-read-write-csv-file-opencsv/
内容来源于网络,如有侵权,请联系作者删除!