JavaFX: Как читать и записывать ObservableList в файл? - PullRequest
0 голосов
/ 01 сентября 2018

Я новичок в программировании, я хочу прочитать / записать данные, которые хранятся в ObservableList, данные из Student класс, который является Strings (firstName и lastName), а также у меня есть TableView для отображения данных.

Вот мой код:

Студенческий класс:

import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;

public class Student implements Serializable {
    private SimpleStringProperty fname;
    private SimpleStringProperty lname;

    Student() {
        this("","");
    }

    Student(String fn, String ln) {
       this.fname = new SimpleStringProperty(fn);
       this.lname = new SimpleStringProperty(ln);
    }


    public void setFirstName(String f) {
        fname.set(f);
    }
    public String getFirstName() {
        return fname.get();
    }

    public void setLastName(String l) {
        lname.set(l);
    }
    public String getLastName() {
        return lname.get();
    }


    @Override
    public String toString() {
        return String.format("%s %s", getFirstName(), getLastName());
    }
}

А вот мой код для ввода данных с использованием TextField s:

    @FXML
    ObservableList<Student> data = FXCollections.observableArrayList();

    //Just to input the data
    @FXML
    private void handleButtonAction(ActionEvent event) {

        if(!"".equals(txtFirstName.getText()) && !"".equals(txtLastName.getText())){
            data.add(
                    new Student(txtFirstName.getText(),
                                txtLastName.getText()
            ));
        }

        txtFirstName.clear();
        txtLastName.clear();

        // System.out.println(data);
    }

А вот и проблема ...

Чтение / запись списка наблюдаемых:

    @FXML
    private void HandleMenuSaveAction(ActionEvent event) {
         try {
            FileOutputStream f = new FileOutputStream(new File("saveStudentList.txt"));
            ObjectOutputStream o = new ObjectOutputStream(f);

            o.writeObject(data);
            o.close();
            f.close();

            System.out.println("File Saved Successfully.");

        } catch (FileNotFoundException ex) {
            System.err.println("Save: File not found.");
        } catch (IOException ex) {
            System.err.println("Save: Error initializing stream.");
            ex.printStackTrace();
        } 
    }

    @FXML
    private void HandleMenuLoadAction(ActionEvent event) {
         try {
            FileInputStream fi = new FileInputStream(new File("saveStudentList.txt"));
            ObjectInputStream oi = new ObjectInputStream(fi);

            data = (ObservableList) oi.readObject();

            System.out.println(data.toString());

            //Refresh the Table everytime we load data

            oi.close();
            fi.close();


        } catch (FileNotFoundException ex) {
            System.err.println("Load: File not found.");
        } catch (IOException ex) {
            System.err.println("Load: Error initializing stream.");
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }

Это вызывает у меня java.io.NotSerializableException, У кого-нибудь есть идеи, как изменить мой код, чтобы он работал?

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Ваш вопрос немного сбивает с толку, так как вы используете сериализацию объектов, но выбранное вами имя файла - .txt. Сериализованные объекты не читаются человеком, как обычный текстовый файл.

Ответ Фабиана выше - это замечательно, если вы хотите использовать сериализацию. Однако, если вы хотите создать простой текстовый файл, взгляните на следующий пример программы:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {

        ObservableList<Student> students = FXCollections.observableArrayList();

        // Create some sample students
        students.addAll(
                new Student("Roger", "Rabbit"),
                new Student("Elmer", "Fudd"),
                new Student("Daffy", "Duck"),
                new Student("Foghorn", "Leghorn"),
                new Student("Betty", "Boop")
        );

        // Write the list to a text file
        try {
            writeToTextFile("students.txt", students);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Now, read the file into a new List<Student>
        List<Student> inputStudents = null;
        try {
             inputStudents = readStudents("students.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Print out the student names
        if (inputStudents != null) {
            for (Student student : inputStudents) {
                System.out.println(student.toString());
            }
        }

    }

    /**
     * Write the list of students to a simple text file with first and last names separated by a comma
     */
    private static void writeToTextFile(String filename, ObservableList<Student> students)
            throws IOException {

        FileWriter writer = new FileWriter(filename);
        for (Student student : students) {
            writer.write(student.getFirstName() + "," + student.getLastName() + "\n");
        }
        writer.close();
    }

    /**
     * Read the comma-separated list of student names from the text file
     */
    private static List<Student> readStudents(String filename)
            throws IOException {

        List<Student> students = new ArrayList<>();

        BufferedReader reader = Files.newBufferedReader(Paths.get(filename));
        String line;
        while ((line = reader.readLine()) != null) {
            String[] names = line.split(",");

            // Add the student to the list
            students.add(new Student(names[0], names[1]));

        }

        return students;
    }
}

Это создает очень простой текстовый файл с именем и фамилией каждого ученика в отдельной строке, разделенных запятой. Затем он читается обратно в новый список, готовый для использования в вашем TableView.

Если вы решите пойти по этому пути, я рекомендую найти хорошую библиотеку CSV для обработки чтения / записи файлов CSV (значения, разделенные запятыми). У Apache Commons есть приличный доступный.

0 голосов
/ 01 сентября 2018

реализовать пользовательскую сериализацию для объекта Student (см. https://stackoverflow.com/a/7290812/2991525) и скопировать содержимое ObservableList в ArrayList, чтобы создать сериализуемый список:

public class Student implements Serializable {

    private void writeObject(ObjectOutputStream out)
            throws IOException {
        out.writeObject(getFirstName());
        out.writeObject(getLastName());
    }

    private void readObject(ObjectInputStream in)
            throws IOException, ClassNotFoundException {
        fname = new SimpleStringProperty((String) in.readObject());
        lname = new SimpleStringProperty((String) in.readObject());
    }

    ...
}

(De) пример сериализации

ObservableList<Student> students = FXCollections.observableArrayList();

for(int i = 0; i < 100; i++) {
    students.add(new Student("Mark"+i, "Miller"+i));
}

ByteArrayOutputStream bos = new ByteArrayOutputStream();

// write list
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
    oos.writeObject(new ArrayList<>(students));
}

students = null; // make sure the old reference is no longer available

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

// read list
try (ObjectInputStream ois = new ObjectInputStream(bis)){
    students = FXCollections.observableList((List<Student>) ois.readObject());
}

System.out.println(students);
...