最近,我需要使用bean读写CSV文件。在此过程中,在研究了数百篇文章之后,我开发了一种功能解决方案。这篇文章是比问题更多的技巧和窍门...希望它可以加快您的工作速度,并避免如果您不遵循这些建议将导致的错误的惊人怪异...
1)要将opencsv与CsvToBean一起使用,您需要在项目中包括所有这些JAR文件(我在Eclipse中将它们作为“外部JAR”添加到了我的构建路径中):
commons-beanutils-1.9.3.jar
commons-collections-3.2.jar
commons-collections4-4.3.jar
commons-lang3-3.8.1.jar
opencsv-4.5.jar
是的-您需要两种版本的commons-collection才能读取和写入bean。
2)构建bean类时,属性和set / get方法必须具有特定的语法,否则您的读/写将失败(opencsv在运行时使用自省和反射)。主要是,您的属性必须全部小写:
Private String ppppp; …
并且get / set例程必须仅将属性的首字母大写:
public String getPpppp() …
public void setPpppp(String value) …
3)使用@CsvBindByName或@CsvBindByPosition 按名称绑定将设置将在读取时映射到该属性的列的名称,按位置绑定将在写入时设置输出顺序。 (如果csv文件中没有标题,bindbyposition还将在读取时设置字段位置。)
@CsvBindByName(column = "ID", required = true)
@CsvBindByPosition(position = 0)
Private String pppppp;
如果该列中的任何数据为空或为空,则不要包含“ required = true”。
4)您的bean类必须具有null构造函数:(如果类名是“ Account”)
public Account() {
}
示例类文件
---------------- Account.java -------------------
package MyCsv;
import java.util.Optional;
import com.opencsv.*;
import com.opencsv.bean.*;
public class Account {
@CsvBindByName(column = "PERSONNEL_ID", required = true)
@CsvBindByPosition(position = 0)
private String personnelid;
@CsvBindByName(column = "LAST_NAME")
@CsvBindByPosition(position = 1)
private String lastname;
// set as constructor
public Account() {
}
public String getPersonnelid()
{
return this.personnelid;
}
public void setPersonnelid(String value)
{
this.personnelid = value;
}
public String getLastname()
{
return this.lastname;
}
public void setLastname(String value)
{
this.lastname = value;
}
@Override
public String toString() {
return "Account [personnelid=" + this.personnelid + ",
“ lastname=" + this.lastname);
}
}
----------------结束Account.java -------------------
5)使用[有状态] CsvToBeanBuilder设置CSV阅读器。
…
List<Account> Accounts = null;
…
try {
Reader freader = new FileReader(inFileName);
HeaderColumnNameMappingStrategy<Account> beanStrategy = new HeaderColumnNameMappingStrategy<Account>();
beanStrategy.setType(Account.class);
CsvToBean<Account> csvToBean = new CsvToBeanBuilder<Account>(freader)
.withType(Account.class)
.withIgnoreLeadingWhiteSpace(true)
.withMappingStrategy(beanStrategy)
.build();
// reads all “Account”s – entire file - into a list of Account beans
Accounts = csvToBean.parse();
freader.close();
}
catch (Exception e)
{
e.printStackTrace();
}
6)使用StatefulBeanToCsvBuilder设置编写器。 (您可以在读写时使用相同的类,前提是您在编写时不更改读取字段的顺序):
Writer writer = new FileWriter(outFileName);
StatefulBeanToCsvBuilder<Account> builder = new StatefulBeanToCsvBuilder<Account>(writer);
StatefulBeanToCsv<Account> beanWriter = builder.build();
// build a header for output & make it the first record in your list
// requires a parameterized constructor (not shown above for brevity)
Account accountHeader = new Account("PersonnelID","LastName");
Accounts.add(0, accountHeader);
try {
// writes all of the account beans in the accounts list at once
beanWriter.write(Accounts);
} catch (CsvDataTypeMismatchException e) {
e.printStackTrace();
} catch (CsvRequiredFieldEmptyException e) {
e.printStackTrace();
}
writer.flush();
writer.close();
7)记住要刷新并关闭“写入”文件,然后关闭读取文件…
8)将所有字段都设为字符串。如果需要输入整数或日期,请在需要时在代码中显式地执行。当bean类具有用int或LocalDate声明的属性时,我得到了无法预料的结果。最简单的方法是在bean类中添加处理转换的get'ers和set'ers:
Public LocalDate getAsDatePpppp() …
Public void setAsDatePpppp(LocalDate theDateToSet) ...