无法正确读取数据

时间:2014-06-26 16:28:35

标签: java csv dozer supercsv

我正在尝试将具有宠物列表的人类持久保存到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如下 -

enter image description here

但是当我把它读回并打印出来时,它打印如下 -

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,如果我有宠物地图而不是列表,我该怎么办。

由于

1 个答案:

答案 0 :(得分:0)

您有2个选项。跳转到快速回答&#39;如果你愿意的话。

继续使用标准CsvBeanReader / Writer

正如您所知,CsvBeanReaderCsvBeanWriter无法处理索引或嵌套映射,因此父类必须有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()

使用CsvDozerBeanReader和CsvDozerBeanWriter

我已经看到了你的另一个问题,所以我知道你已经考虑过使用推土机扩展。在这种情况下,我真的推荐它。要获取上面建议的CSV文件,您可以使用以下命令配置fieldMapping:

setPets()

不必担心任何自定义单元处理器。如果你有很多宠物,你可以像我在other问题中建议的那样动态创建fieldMapping。