我正在尝试将具有宠物列表的人类持久保存到CSV文件并将其读回相应的对象。我能够正确地写它但无法阅读。请看下面 -
Person.java
import java.util.ArrayList;
import java.util.List;
public class Person {
private String name;
private List<Pet> pets;
public Person() {
}
public Person(final String name, final List<Pet> pets) {
this.name = name;
this.pets = pets;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the pets
*/
public List<Pet> getPets() {
return pets;
}
/**
* @param pets
* the pets to set
*/
public void setAddPet(final Pet pet) {
if (pets == null) {
pets = new ArrayList<Pet>();
}
pets.add(pet);
}
/**
* @param name
* the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* @param pets
* the pets to set
*/
public void setPets(final List<Pet> pets) {
this.pets = pets;
}
@Override
public String toString() {
return String.format("Person [name=%s, pets=%s]", name, pets);
}
}
Pet.java
public class Pet {
private String typeOfAnimal;
private String color;
public Pet() {
}
public Pet(final String typeOfAnimal, final String color) {
this.typeOfAnimal = typeOfAnimal;
this.color = color;
}
/**
* @return the color
*/
public String getColor() {
return color;
}
/**
* @return the typeOfAnimal
*/
public String getTypeOfAnimal() {
return typeOfAnimal;
}
/**
* @param color
* the color to set
*/
public void setColor(final String color) {
this.color = color;
}
/**
* @param typeOfAnimal
* the typeOfAnimal to set
*/
public void setTypeOfAnimal(final String typeOfAnimal) {
this.typeOfAnimal = typeOfAnimal;
}
@Override
public String toString() {
return String.format("Pet [typeOfAnimal=%s, color=%s]", typeOfAnimal, color);
}
}
Writer.java
import java.io.FileWriter;
import java.util.Arrays;
import java.util.List;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.dozer.CsvDozerBeanWriter;
import org.supercsv.io.dozer.ICsvDozerBeanWriter;
import org.supercsv.prefs.CsvPreference;
public class Writer {
private static final String[] HEADERS = new String[] { "name", "pets" };
private static final CellProcessor[] processors = new CellProcessor[] { new NotNull(),
new NotNull() };
private static final String CSV_FILENAME = "C:\\Users\\Desktop\\Test.csv";
public static void writeWithDozerCsvBeanWriter() throws Exception {
// create the survey responses to write
final Person person1 = new Person("Dereck", Arrays.asList(new Pet("Dog",
"Black")));
final Person person2 =
new Person("Gavin", Arrays.asList(new Pet("Squirrel", "Brown"), new Pet("Cat",
"White")));
final List<Person> people = Arrays.asList(person1, person2);
ICsvDozerBeanWriter beanWriter = null;
try {
beanWriter =
new CsvDozerBeanWriter(new FileWriter(CSV_FILENAME),
CsvPreference.STANDARD_PREFERENCE);
// configure the mapping from the fields to the CSV columns
beanWriter.configureBeanMapping(Person.class, HEADERS);
// write the header
beanWriter.writeHeader(HEADERS);
// write the beans
for (final Person person : people) {
beanWriter.write(person, processors);
}
} finally {
if (beanWriter != null) {
beanWriter.close();
}
}
}
}
Reader.java
import java.io.FileReader;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.CsvBeanReader;
import org.supercsv.io.ICsvBeanReader;
import org.supercsv.prefs.CsvPreference;
public class Reader {
private static final String CSV_FILENAME = "C:\\Users\\Desktop\\Test.csv";
/**
* An example of reading using CsvBeanReader.
*/
public static void readWithCsvBeanReader() throws Exception {
ICsvBeanReader beanReader = null;
try {
beanReader =
new CsvBeanReader(new FileReader(CSV_FILENAME),
CsvPreference.STANDARD_PREFERENCE);
// the header elements are used to map the values to the bean (names must
match)
final String[] header = beanReader.getHeader(true);
// set up the field mapping and processors dynamically
final String[] fieldMapping = new String[header.length];
final CellProcessor[] processors = new CellProcessor[header.length];
for (int i = 0; i < header.length; i++) {
if (i < 1) {
// normal mappings
fieldMapping[i] = header[i];
processors[i] = new NotNull();
} else {
// attribute mappings
fieldMapping[i] = "AddPet";
processors[i] = new Optional(new ParsePersonPet(header));
}
}
Person person;
while ((person = beanReader.read(Person.class, fieldMapping, processors)) !=
null) {
System.out.println(String.format("person=%s", person));
}
} finally {
if (beanReader != null) {
beanReader.close();
}
}
}
}
ParsePersonPet.java
import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.util.CsvContext;
public class ParsePersonPet extends CellProcessorAdaptor {
private final String[] header;
public ParsePersonPet(final String[] header) {
this.header = header;
}
@Override
public Object execute(final Object value, final CsvContext context) {
if (value == null) {
return null;
}
final Pet pet = new Pet();
pet.setTypeOfAnimal((String) value);
return pet;
}
}
目前,它被写入csv如下 -
但是当我把它读回并打印出来时,它打印如下 -
person=Person [name=Dereck, pets=[Pet [typeOfAnimal=[Pet [typeOfAnimal=Dog,
color=Black]], color=null]]]
person=Person [name=Gavin, pets=[Pet [typeOfAnimal=[Pet [typeOfAnimal=Squirrel,
color=Brown], Pet [typeOfAnimal=Cat, color=White]], color=null]]]
我知道问题出在 ParsePersonPet.java
pet.setTypeOfAnimal((String) value);
但是值似乎以字符串形式返回Pet [typeOfAnimal=Dog, color=Black]
我是否必须使用字符串标记符并设置适当的值?这可能很乏味吗?我该怎么办?
由于
更新:我通过将ParsePersonPet更改为以下代码来实现工作 -
import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.util.CsvContext;
public class ParsePersonPet extends CellProcessorAdaptor {
private final String[] header;
public ParsePersonPet(final String[] header) {
this.header = header;
}
@Override
public Object execute(final Object value, final CsvContext context) {
if (value == null) {
return null;
}
final String str = (String) value;
final Pet pet = new Pet();
pet.setTypeOfAnimal(getValue("typeOfAnimal", str));
pet.setColor(getValue("color", str));
return pet;
}
public String getValue(final String strValueToSearchFor, final String str) {
if (str.contains(strValueToSearchFor)) {
final int startIndex =
str.lastIndexOf(strValueToSearchFor) + strValueToSearchFor.length() + 1;
int endIndex = str.indexOf(",", startIndex);
if (endIndex == -1) {
endIndex = str.indexOf("]", startIndex);
}
return str.substring(startIndex, endIndex);
}
return null;
}
}
我需要知道如何避免使用setAddpet并使用setPets,如果我有宠物地图而不是列表,我该怎么办。
由于
答案 0 :(得分:0)
您有2个选项。跳转到快速回答&#39;如果你愿意的话。
正如您所知,CsvBeanReader
和CsvBeanWriter
无法处理索引或嵌套映射,因此父类必须有getter / setter才能访问子类& #39;字段。
执行单元处理器后,Super CSV会在值上调用toString()
,然后根据需要转义任何嵌入的逗号,引号和换行符。因此,在您的作者中,NotNull()
确保List不为null后,它只是执行toString()
并转义。所以基本上你最终会在CSV文件中找到一个宠物专栏。
如果您想为每只宠物添加一列,您必须拥有一个单独的吸气剂(getPet1()
,getPet2()
等),只需访问列表中的所需宠物即可。你必须知道你想要支持多少只宠物 - CSV不应该有可变列。我想象你实际上想要每只宠物有两列 - 动物类型和颜色 - 所以你可以有不同的吸气剂((getPet1Type()
,getPet1Color()
等)或者写2个单元处理器(FmtPetType和FmtPetColor),只返回类型或颜色。
所以你的CSV文件看起来像是:
name,pet1Type,pet1Color,pet2Type,pet2Color
Jo,Dog,Black,Cat,White
快速回答
否则,如果您想保留toString
宠物清单(知道您的CSV文件更难让其他人解析),您需要编写一个可以接受{的自定义单元处理器{1}}列出并再次将其解析为宠物列表。这有点痛苦,但可行。那时你不需要toString()
方法,因为它可以简单地使用setAddPet()
。
我已经看到了你的另一个问题,所以我知道你已经考虑过使用推土机扩展。在这种情况下,我真的推荐它。要获取上面建议的CSV文件,您可以使用以下命令配置fieldMapping:
setPets()
不必担心任何自定义单元处理器。如果你有很多宠物,你可以像我在other问题中建议的那样动态创建fieldMapping。