Dateiverarbeitung - Wortliste abspeichern & Wörter zählen

Einen wunderschönen Guten Tag wünsche ich jedem Lesenden und im allgemeinen der Java-Gemeinde.

Ich hänge aktuell an einer Aufgabe fest die mir mehr Schwierigkeiten bereitet als gedacht...

Ich soll einen Editor erstellen, mit dem ich eine Wortliste in einer Datei ablegen kann.
Jedoch sollen nicht nur die Wörter an sich abgespeichert werden, sondern auch die Anzahl der gespeicherten Wörter...

Ich bekomme es schon mal hin das die Wörter in die Datei geschrieben und auch wieder raus gegeben werden.
Das Zählen der Wörter bereitet aktuell noch Probleme.. ich würde die Zahl gerne an den Anfang der Datei schreiben und dann
immer wieder aktualisieren.. also die Zahl aus der 1. Zeile quasi löschen und ersetzen..

hat jemand eine Idee ?? vielleicht ist der Lösungsansatz ja komplett falsch und ich muss irgendwas mit der Random access class machen..?

der von mir erstellte Quelltext sieht bislang so aus..

Java:
package aufgabe1;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class Texteditor extends JFrame {
    //automatisch über Eclipse ergänzt
    private static final long serialVersionUID = 6468516705291496250L;
    //für das Eingabefeld
    private JTextArea feld;
    //für die Schaltflächen
    private JButton einlesen, beenden, schreiben;
    
//
    private int anzahlWoerter = 0;
//
    
    //die innere Klasse für den ActionListener
    class MeinListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            //wurde auf Lesen geklickt?
            if (e.getActionCommand().equals("lesen"))
                //dann die Datei einlesen
                dateiLesen();
            //wurde auf Schreiben geklickt?
            if (e.getActionCommand().equals("schreiben"))
                //dann die Datei schreiben
                dateiSchreiben();
            //wurde auf Beenden geklickt?
            if (e.getActionCommand().equals("ende"))
                System.exit(0);
        }
    }

    //der Konstruktor
    public Texteditor(String titel) {
        super(titel);
        //für das Panel mit den Schaltflächen
        JPanel tempPanel;
        //ein neues Eingabefeld erstellen
        feld = new JTextArea();
        //die Schaltflächen
        einlesen = new JButton("Einlesen");
        einlesen.setActionCommand("lesen");
        schreiben = new JButton("Schreiben");
        schreiben.setActionCommand("schreiben");
        beenden = new JButton("Beenden");
        beenden.setActionCommand("ende");
        
        MeinListener listener = new MeinListener();
        einlesen.addActionListener(listener);
        schreiben.addActionListener(listener);
        beenden.addActionListener(listener);
                
        //ein BorderLayout anwenden
        setLayout(new BorderLayout());
        //das Eingabefeld mit Scrollbars
        add(new JScrollPane(feld), BorderLayout.CENTER);
        //ein Panel für die Schaltflächen
        tempPanel = new JPanel();
        tempPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        tempPanel.add(einlesen);
        tempPanel.add(schreiben);
        tempPanel.add(beenden);
        add(tempPanel,BorderLayout.SOUTH);
        
        //Größe setzen, Standard-Verhalten festlegen und anzeigen
        setMinimumSize(new Dimension(400,300));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    //die Methode zum Lesen
    private void dateiLesen() {
        //eine Instanz der Klasse FileReader mit der Datei daten.txt
        try (FileReader datei = new FileReader("Listendaten.txt")){
            //in das Textfeld lesen
            feld.read(datei, null);
        }
        catch (IOException e ) {
            JOptionPane.showMessageDialog(this, "Beim Laden ist ein Problem aufgetreten");
        }
    }

    //die Methode zum Schreiben
    private void dateiSchreiben() {
        //eine Instanz der Klasse FileWriter mit der Datei daten.txt
        //true im Konstruktor setzen, damit ein neues Wort ganz einfach hinzugefügt werden kann,
        //ohne das vorherige Wort zu überschreiben
        try (FileWriter datei = new FileWriter("Listendaten.txt", true)){
            //die Anzahl der Worte in die 1. Zeile der Datei schreiben
            datei.append(String.valueOf(anzahlWoerter)).append("\n");
            
            //den Inhalt ausdem Textfeld + einen Zeilensprung
            //in die Datei "Listendaten.txt" einfügen
            datei.append(feld.getText()).append("\n");
            
            //die Methode zum Hochzählen der Worte aufrufen
            woerterZaehlen();
        }
        catch (IOException e ) {
            JOptionPane.showMessageDialog(this, "Beim Schreiben ist ein Problem aufgetreten");
        }
    }

    private int woerterZaehlen() {
        anzahlWoerter++;
        return anzahlWoerter;
    }
}
 

KonradN

Super-Moderator
Mitarbeiter
Also erst einmal ein allgemeiner Hinweis zu funktionaler Programmierung speziell sogenannten Lambdas: Du kannst eine Art anonyme Methode weitergeben. Dabei hast Du erst die Parameter ohne Typen, ein "Pfeil" und dann Code, der den Aufruf macht.

Wenn ein Interface nur die Implementation einer Methode fordert, dann nennt man das funktionales Interface und wie Du siehst: ActionListener hat nur genau eine Methode, die implementiert werden muss.

Wenn Du nun ein funktionales Interface angeben musst, dann kannst Du an der Stelle ein Lambda Ausdruck angeben. In Deinem Fall ist es eine Methode mit einem Parameter: ActionEvent e. Somit kann ein Lambda so aussehen: e -> dateiLesen().

Das kannst Du jetzt umsetzen in deinem Code:
a) Die innere Klasse entfällt komplett. Dieser Code wird also gelöscht:
Java:
    class MeinListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            //wurde auf Lesen geklickt?
            if (e.getActionCommand().equals("lesen"))
                //dann die Datei einlesen
                dateiLesen();
            //wurde auf Schreiben geklickt?
            if (e.getActionCommand().equals("schreiben"))
                //dann die Datei schreiben
                dateiSchreiben();
            //wurde auf Beenden geklickt?
            if (e.getActionCommand().equals("ende"))
                System.exit(0);
        }
    }

b) Den Block, wo du dies nutzt, verändert sich nun. Aus:
Java:
        MeinListener listener = new MeinListener();
        einlesen.addActionListener(listener);
        schreiben.addActionListener(listener);
        beenden.addActionListener(listener);

wird nun einfach:
Java:
        einlesen.addActionListener( e -> dateiLesen() );
        schreiben.addActionListener( e -> dateiSchreiben() );
        beenden.addActionListener( e -> System.exit(0) );

Das macht den Code dann deutlich lesbarer (kürzer und Du hast bei der Zuweisung direkt die jeweiligen Aufrufe, d.h. es ist direkt ersichtlich, was da aufgerufen wird).

Bezüglich der eigentlichen Problematik schreibe ich direkt im Anschluss etwas.
 

KonradN

Super-Moderator
Mitarbeiter
Um in eine Datei erst die Anzahl zu schreiben und dann die Worte, kannst Du prinzipiell so machen, wie bisher. Wenn Du in der ersten Zeile aber die Anzahl hast, dann musst du das natürlich noch erweitern:
Java:
        try (FileReader datei = new FileReader("Listendaten.txt")){
            // TODO: Hier muss erst die erste Zeile gelesen werden

            //in das Textfeld lesen
            feld.read(datei, null);
        }

Jetzt ist nur die Frage: Wie liest man am einfachsten die erste Zeile?

a) FileReader - der kann das natürlich. Einfach per read Zeichen für Zeichen lesen, alles zusammen bauen und dann bei dem Newline Aufhören zu lesen. Die Zeichen müssen dann natürlich zusammengebaut werden zu dem eigentlichen Wert um diesen dann in ein int Umzuwandeln.

b) Es gibt natürlich Reader, die das schon alles können. Hier kommt dann der BufferedReader ins Spiel. Gebaut wird dieser einfach mit einem verschachtelten Aufruf - der gebaute FileReader wird im Konstruktor übergeben:
Java:
try (BufferedReader datei = new BufferedReader(new FileReader("Listendaten.txt")){
Das lesen einer Zeile ist dann einfach ein readLine() Aufruf.
 
erst einmal danke ich dir für die Mühe..
aber ich bin ehrlich zu dir.. ich verstehe das alles nicht so ganz.
Damit meine ich wo ich was einsetzen muss und so weiter..

Dazu kommt ja noch das Problem dass ich die zwischennummern nicht mit lesen möchte..
 

Neue Themen


Oben