java - 使用 TextFields 将学生的 ArrayList 存储在文件中

标签 java swing arraylist

我制作了一个小型 java swing 应用程序,将学生列表存储在文件 students.txt 中。 但我在将许多学生保存到文件中时遇到一个问题: 当我点击“保存”按钮时,只存储了一份学生记录。如果我在文本字段中输入新数据并再次单击“保存”按钮,它只会保存新创建的学生,覆盖旧记录,而我希望将新学生附加到文件中的现有学生列表中。

这是我的代码:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class studentTest extends JFrame {

    JPanel p1, p2, p3, p4, p5, p6;
    JTextField f1, f2, f3, f4;
    JLabel l1, l2, l3, l4;
    JButton b1, b2, b3;

    public studentTest() {
        setBounds(100, 150, 300, 400);
        b1 = new JButton("Save");
        b1.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                List<Student> Students = new ArrayList();
                Student newStudents = new Student();
                newStudents.setStudentFName(f1.getText());
                newStudents.setStudentLName(f2.getText());
                newStudents.setGPA(f4.getText());
                newStudents.setID(f3.getText());
                Students.add(newStudents);

                        try{

                        PrintWriter pw = new PrintWriter(new FileOutputStream("/Users/Yukki/Desktop/Students.txt"));
                        pw.println(newStudents+"\n"); 
                        pw.close();

                        } catch (FileNotFoundException ex) {

                        }

                    }

        });
        b2 = new JButton("First Record");
        b3 = new JButton("Next");
        l1 = new JLabel("  FirstName :");
        l2 = new JLabel("  LastName :");
        l3 = new JLabel("  ID :");
        l4 = new JLabel("  GPA :");
        f1 = new JTextField(10);
        f2 = new JTextField(10);
        f3 = new JTextField(10);
        f4 = new JTextField(10);
        p1 = new JPanel(new GridLayout(1, 2));
        p1.add(l1);
        p1.add(f1);
        p2 = new JPanel(new GridLayout(1, 2));
        p2.add(l2);
        p2.add(f2);
        p3 = new JPanel(new GridLayout(1, 2));
        p3.add(l3);
        p3.add(f3);
        p4 = new JPanel(new GridLayout(1, 2));
        p4.add(l4);
        p4.add(f4);
        p5 = new JPanel(new GridLayout(1, 1));
        p5.add(b1);
        p6 = new JPanel(new GridLayout(1, 2));
        p6.add(b2);
        p6.add(b3);
        setLayout(new GridLayout(6, 1));
        add(p1);
        add(p2);
        add(p3);
        add(p4);
        add(p5);
        add(p6);
    }

    public static void main(String[] args) {
        (new studentTest()).show();



    }
}

最佳答案

虽然您可以尝试多种解决方案,但我会推荐。尝试使用Java Architecture for XML Binding (JAXB) ,因为它将允许您定义将 Student 实例输出到 XML 的方法。

从那里,它应该允许您将多个实例添加到同一个文件中。

可能会建议您序列化对象,但就我个人而言,我会避免这样做。它仅用于对象的短期存储,通常用于通过线路传输,但这只是我的观点......

更新示例...

这是基于 JAXB exmaple: Marshalling and Unmarshalling list or set of objects 中的示例和 JAXB Hello World Example

首先,我们需要定义 Student 类和 JAXB 注释。这使我们能够描述应该如何编码(翻译)对象的实例

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Student {

    String name;
    int age;
    int id;

    // This is a requirement of JAXB...
    public Student() {
    }

    public Student(int id, String name, int age) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @XmlElement
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    @XmlElement
    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    @XmlAttribute
    public void setId(int id) {
        this.id = id;
    }

}

接下来,我们需要创建一个可以包含对象列表的简单包装类。这是必需的,以便 JAXB API 可以更轻松地访问内部数据...

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType (XmlAccessType.FIELD)
@XmlRootElement
public class Students implements Iterable<Student> {

    private List<Student> students;

    public Students() {
        this.students = new ArrayList<>(25);
    }

    public Student get(int index) {
        return students.get(index);
    }

    public void add(Student student) {
        students.add(student);
    }

    public void remove(Student student) {
        students.remove(student);
    }

    public int size() {
        return students.size();
    }

    @Override
    public String toString() {
        return "List-o-Students: " + size();
    }

    @Override
    public Iterator<Student> iterator() {
        return students.iterator();
    }

}

最后,我们需要测试它......

import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.jaxb.test.Student;
import org.jaxb.test.Students;

public class JAXBExample {

    public static void main(String[] args) {

        Students students = new Students();
        students.add(new Student(100, "Bob", 29));
        students.add(new Student(101, "John", 19));
        students.add(new Student(102, "Joe", 39));
        students.add(new Student(103, "Jane", 25));

        try {

            File file = new File("file.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(Students.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            jaxbMarshaller.marshal(students, file);
            jaxbMarshaller.marshal(students, System.out);

        } catch (JAXBException e) {
            e.printStackTrace();
        }
        try {

            File file = new File("file.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(Students.class);

            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            students = (Students) jaxbUnmarshaller.unmarshal(file);
            System.out.println(students);

        } catch (JAXBException e) {
            e.printStackTrace();
        }

    }

}

哪个输出...

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<students>
    <students id="100">
        <age>29</age>
        <name>Bob</name>
    </students>
    <students id="101">
        <age>19</age>
        <name>John</name>
    </students>
    <students id="102">
        <age>39</age>
        <name>Joe</name>
    </students>
    <students id="103">
        <age>25</age>
        <name>Jane</name>
    </students>
</students>
List-o-Students: 4

已更新可更新示例

下面允许您动态更新 XML 加类。它与读、写、读的概念几乎相同,但提供了一些附加功能......

try {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    File xml = new File("file.xml");
    Document document = db.parse(xml);

     // Create a new context...
    JAXBContext jc = JAXBContext.newInstance(Students.class);

    // Create a new Binder from the context
    Binder<Node> binder = jc.createBinder();
    // Load the document
    Students students = (Students) binder.unmarshal(document);

    // Update the student at position 0
    Student student = students.get(0);
    student.setAge(100);

    // Add a new student
    students.add(new Student(200, "Harry", 65));

    // Update the document
    binder.updateXML(students);

    // Write the contents back to the file..
    FileOutputStream fos = null;
    try {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        fos = new FileOutputStream(xml);
        t.transform(new DOMSource(document), new StreamResult(fos));
    } catch (TransformerFactoryConfigurationError | TransformerException exp) {
        exp.printStackTrace();
    } finally {
        try {
            fos.close();
        } catch (Exception e) {
        }
    }
} catch (ParserConfigurationException | SAXException | IOException | JAXBException exp) {
    exp.printStackTrace();
}

这可能看起来有点复杂,但这意味着您现在可以动态修改底层文档。

不过,为了满足您的需求,我会简单地在开始时读取现有列表,更新列表,最后,当您准备好时,将其写回...但这只是我...

最后,一个完全可运行的示例......

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.bind.Binder;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jaxb.test.Student;
import org.jaxb.test.Students;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

public class JAXBExample {

    public static void main(String[] args) {

        Students students = new Students();
        students.add(new Student(100, "Bob", 29));
        students.add(new Student(101, "John", 19));
        students.add(new Student(102, "Joe", 39));
        students.add(new Student(103, "Jane", 25));

        write(students);
        students = null;
        students = read();

        for (Student student : students) {
            System.out.println(student);
        }

        update();

        students = null;
        students = read();

        for (Student student : students) {
            System.out.println(student);
        }

    }

    public static void write(Students students) {

        System.out.println("----> Write");
        try {

            File file = new File("file.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(Students.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            jaxbMarshaller.marshal(students, file);
//            jaxbMarshaller.marshal(students, System.out);

        } catch (JAXBException e) {
            e.printStackTrace();
        }

    }

    public static Students read() {

        System.out.println("----< Read");
        Students students = null;
        try {

            File file = new File("file.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(Students.class);

            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            students = (Students) jaxbUnmarshaller.unmarshal(file);
            System.out.println(students);

        } catch (JAXBException e) {
            e.printStackTrace();
        }

        return students;

    }

    public static void update() {

        System.out.println("----> Update");
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            File xml = new File("file.xml");
            Document document = db.parse(xml);

            JAXBContext jc = JAXBContext.newInstance(Students.class);

            Binder<Node> binder = jc.createBinder();
            Students students = (Students) binder.unmarshal(document);

            Student student = students.get(0);
            student.setAge(100);

            students.add(new Student(200, "Harry", 65));

            binder.updateXML(students);

            FileOutputStream fos = null;
            try {
                TransformerFactory tf = TransformerFactory.newInstance();
                Transformer t = tf.newTransformer();
                fos = new FileOutputStream(xml);
                t.transform(new DOMSource(document), new StreamResult(fos));
            } catch (TransformerFactoryConfigurationError | TransformerException exp) {
                exp.printStackTrace();
            } finally {
                try {
                    fos.close();
                } catch (Exception e) {
                }
            }
        } catch (ParserConfigurationException | SAXException | IOException | JAXBException exp) {
            exp.printStackTrace();
        }
    }

}

关于java - 使用 TextFields 将学生的 ArrayList 存储在文件中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20829001/

相关文章:

java awt 或 Swing 组件丢失或未显示

java - 如何将数字转换为ascii值或字符并存储在字符串数组中

java - 通过 Intent 返回字符串的 ArrayList 时,我得到 null 值

java - 如何使用 libgdx 绘制边界线内的图像部分?

java - 如何在带有通配符的泛型映射中使用带有类型化参数的泛型集合 (Java)

java - 从枚举填充 Swing JComboBox

Java Swing 按钮: setColor doesn't display the right color

java - 调用数组列表方法

java - JButton "disappears"尽管它位于 JLabel 之外的另一层

Java - KeyListener 的线程导致并发修改。解决方案?