【问题标题】:Unable to read the data back properly [duplicate]无法正确读取数据[重复]
【发布时间】:2014-06-26 16:28:35
【问题描述】:

我正在尝试将具有宠物列表的人员类持久保存到 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] 的字符串形式返回,我是否必须使用 String Tokenizer 并设置适当的值?这可能很乏味吧?我在这里做什么?

谢谢

更新:我通过将 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 以及如果我有宠物地图而不是列表该怎么办。

谢谢

【问题讨论】:

    标签: java csv dozer supercsv


    【解决方案1】:

    您有 2 个选项。如果需要,请跳至“快速回答”。

    继续使用标准 CsvBeanReader/Writer

    如您所知,CsvBeanReaderCsvBeanWriter 无法处理索引或嵌套映射,因此父类上必须有 getter/setter 才能访问子类的字段。

    在单元处理器执行后,Super CSV 将对值调用toString(),然后根据需要转义任何嵌入的逗号、引号和换行符。因此,在您的作家中,在NotNull() 确保列表不为空之后,它只是在执行toString() 并转义。因此,基本上您最终会在 CSV 文件中得到一个宠物列。

    如果您想为每只宠物设置一个列,则必须有一个单独的 getter(getPet1()getPet2() 等),它可以简单地访问列表中所需的宠物。您必须知道要支持多少只宠物 - CSV 不应该有可变列。我想象你实际上想要为每只宠物提供 2 列——动物类型和颜色——所以你可以有不同的吸气剂((getPet1Type()getPet1Color() 等),或者编写 2 个单元处理器(FmtPetType 和 FmtPetColor)只返回类型或颜色。

    所以你的 CSV 文件看起来像:

    name,pet1Type,pet1Color,pet2Type,pet2Color
    Jo,Dog,Black,Cat,White
    

    快速回答

    否则,如果您想保留 toString 宠物列表(知道您的 CSV 文件更难被其他人解析),您需要编写一个可以接收 toString()'d 的自定义单元处理器list 并再次将其解析为宠物列表。这有点痛苦,但可行。你就不需要setAddPet() 方法,因为它可以简单地使用setPets()

    使用 CsvDozerBeanReader 和 CsvDozerBeanWriter

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

    String[] fieldMapping = {"name","pets[0].typeOfAnimal","pets[0].color",
        "pets[1].typeOfAnimal","pets[1].color"};
    

    而且不必担心任何定制单元处理器。如果您有很多宠物,您可以按照我在other 问题中的建议简单地动态创建 fieldMapping。

    【讨论】:

    • 感谢您的回答。我可以使用索引映射,但目前我们有大约 6000 人,其中大约 100 人有大约 10 只宠物,其中我们再次有多个嵌套对象,其中我们再次嵌套对象:( 所以我认为对于我们的应用程序..快速回答最好避免太多列?请建议。另外 - 我如何避免 setAddpet 方法,如果宠物要成为地图我该怎么办?我们的应用程序中结合了列表和地图。
    猜你喜欢
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 2019-10-15
    • 1970-01-01
    相关资源
    最近更新 更多