Невозможно правильно прочитать данные обратно

Я пытаюсь сохранить класс человека, у которого есть список домашних животных, в файл 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, а также что мне делать, если у меня вместо списка есть карта домашних животных.

Спасибо

1 ответ

У вас есть 2 варианта. Перейдите к "Быстрый ответ", если хотите.

Продолжайте использовать стандартный CsvBeanReader/Writer

Как вы знаете, CsvBeanReader а также CsvBeanWriter не может обрабатывать индексированные или вложенные отображения, поэтому для доступа к полям дочернего класса должны быть методы получения / установки родительского класса.

Super CSV выполнит вызов сотового процессора toString() на значение затем экранируйте запятые, кавычки и переводы строк, если это необходимо. Так в вашем писателе, после NotNull() убедитесь, что список не является нулевым, он просто делает toString() и сбежать. Таким образом, в конечном итоге вы получите один столбец с домашними животными в файле CSV.

Если бы вы хотели столбец для каждого питомца, вы должны иметь отдельный получатель (getPet1(), getPet2()и т. д.), который просто получает доступ к нужному питомцу в списке. Вы должны знать, сколько питомцев вы хотите поддерживать - в CSV не должно быть переменных столбцов. Я представляю, что вы на самом деле хотите 2 колонки для каждого питомца - тип и цвет животного - чтобы у вас могли быть разные добытчики ((getPet1Type(), getPet1Color()и т. д.) или напишите процессоры с 2 ячейками (FmtPetType и FmtPetColor), которые просто возвращают тип или цвет.

Таким образом, ваш CSV-файл будет выглядеть примерно так:

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

Быстрый ответ

В противном случае, если вы хотите сохранить toString список домашних животных (зная, что ваш CSV-файл труднее для анализа другими людьми), вам нужно написать собственный процессор для ячеек, который может принять toString()перечислим и снова разберем его в списке домашних животных. Это немного больно, но выполнимо. Вам не понадобится setAddPet() метод, так как он мог бы просто использовать setPets(),

Используйте CsvDozerBeanReader и CsvDozerBeanWriter

Я видел ваш другой вопрос, так что я знаю, что вы уже использовали расширение dozer. В этом случае я бы порекомендовал это. Чтобы получить CSV-файл, который я предложил выше, вы можете настроить fieldMapping с помощью:

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

И не нужно беспокоиться о каких-либо пользовательских процессорах ячеек. Если у вас много домашних животных, вы можете просто создать динамическое отображение поля, как я предложил в вашем другом вопросе.

Другие вопросы по тегам