Integer aus Textdatei auslesen

Einen wunderschönen Guten Tag,

ich muss als Unterrichtsprojekt innerhalb eines Jahres ein kleines Spiel meiner Wahl in Java entwerfen. Java hatten wir in der Schule jetzt fatalerweise nur 3 Monate kurz angeschnitten, weshalb ich manchmal etwas amateurhaft mal nachfragen muss, was ich wo falsch gemacht habe. Es geht aktuell sehr gut voran!
Eine Frage hätte ich da. Ich möchte gerne meinen Spielstand abspeichern, wenn ich das Spiel schließe und beim erneuten Öffnen den Spielstand wieder abrufen.

Hierzu habe ich in mein Javaverzeichnis die Datei “spielstand.txt” integriert. Das Spiel bezieht sich auf zahlreiche Integer, die im Hintergrund alle möglichen Algorithmen des Spiels steuern.
Meine Textdatei sieht zum Beispiel so aus:

gastkarten:100
laenderkarten:24
spieleramzug:2
punktespieler1:37
punktespieler2:45

Durch den Doppelpunkt getrennt sind einerseits die einzuspeichernde Variable und auf der rechten Seite stehts der Wert, den ich einfügen möchte.

Was ich erreichen möchte ist nun, dass das Programm beim aufrufen sofort überprüft, ob spielstand.txt vorhanden ist und dann die Zeilen absucht und in die Variablen abspeichert.
Also hab ich beispielsweise die Variable punktespieler1 und er soll die Zeile suchen und die Zahl die hinter dem Doppelpunkt steht brav in den gleichnamigen Integer reinschreiben.

Ich hab viel gegooglet, aber ehrlich gesagt bisher nicht viel verstanden, was dort alles erklärt wird. Kann mir da jemand kurz weiterhelfen?
Mein bisheriger Programmcode ist dieser:

import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;

public class CafeRoot extends JFrame {
  // Anfang Attribute
  private JLabel jLabelRestkartenTisch = new JLabel();
  private JLabel jLabelRestkartenGast = new JLabel();
  private JLabel jLabelRestbarplaetze = new JLabel();
  private JLabel jLabelHandkartenSpieler1 = new JLabel();
  private JLabel jLabelHandkartenSpieler2 = new JLabel();
  private JLabel jLabelPunkteSpieler1 = new JLabel();
  private JLabel jLabelPunkteSpieler2 = new JLabel();
  private JLabel jLabelSpieler = new JLabel();
  private JList jListGastkarten = new JList();
  //private DefaultListModel jListGastkartenModel = new DefaultListModel();
  //private JScrollPane jListGastkartenScrollPane = new JScrollPane(jListGastkarten);
  // Ende Attribute
  
  public CafeRoot(String title) { 
    // Frame-Initialisierung
    super(title);
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    
    int frameWidth = 468; 
    int frameHeight = 434;
    setSize(frameWidth, frameHeight);
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (d.width - getSize().width) / 2;
    int y = (d.height - getSize().height) / 2;
    setLocation(x, y);
    setResizable(false);
    Container cp = getContentPane();
    setTitle("Café International");
    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    setLocationRelativeTo(null);
    cp.setLayout(null);
    
    // Anfang Komponenten
    int restkartentisch = 24;
    jLabelRestkartenTisch.setBounds(25, 10, 100, 30);
    jLabelRestkartenTisch.setText("Resttische: "+restkartentisch);
    cp.add(jLabelRestkartenTisch);
    //=============================
    int restkartengast = 0; //werden noch gemischt
    jLabelRestkartenGast.setBounds(25, 35, 100, 30);
    jLabelRestkartenGast.setText("Restgäste: "+restkartengast);
    cp.add(jLabelRestkartenGast);
    //=============================
    int restbarplaetze = 21;
    jLabelRestbarplaetze.setBounds(25, 60, 120, 30);
    jLabelRestbarplaetze.setText("Barplätze übrig: "+restbarplaetze);
    cp.add(jLabelRestbarplaetze);
    //=============================
    int handkartenspieler1 = 0;//werden noch ausgeteilt
    jLabelHandkartenSpieler1.setBounds(25, 85, 140, 30);
    jLabelHandkartenSpieler1.setText("Karten Spieler 1: "+handkartenspieler1);
    cp.add(jLabelHandkartenSpieler1);
    //=============================
    int handkartenspieler2 = 0;
    jLabelHandkartenSpieler2.setBounds(25, 110, 140, 30);
    jLabelHandkartenSpieler2.setText("Karten Spieler 2: "+handkartenspieler2);
    cp.add(jLabelHandkartenSpieler2);
    //=============================
    int punktespieler1 = 0;
    jLabelPunkteSpieler1.setBounds(25, 135, 140, 30);
    jLabelPunkteSpieler1.setText("Pkt. Spieler 1: "+punktespieler1);
    cp.add(jLabelPunkteSpieler1);
    //=============================
    int punktespieler2 = 0;
    jLabelPunkteSpieler2.setBounds(25, 160, 140, 30);
    jLabelPunkteSpieler2.setText("Pkt. Spieler 2: "+punktespieler2);
    cp.add(jLabelPunkteSpieler2);
    //=============================
    int spieler = 1;
    jLabelSpieler.setBounds(25, 185, 140, 30);
    jLabelSpieler.setText("Am Zug: Spieler "+spieler);
    cp.add(jLabelSpieler);
    //=============================
    DefaultListModel jListGastkartenModel = new DefaultListModel();
    JList jList = new JList(jListGastkartenModel);
    JScrollPane jListGastkartenScrollPane = new JScrollPane(jListGastkarten);
    jListGastkarten.setModel(jListGastkartenModel);
    jListGastkartenScrollPane.setBounds(25, 210, 297, 121);
    cp.add(jListGastkartenScrollPane);
    jListGastkarten.setVisible(true);
    // Ende Komponenten
    
    setVisible(true);
    addWindowListener(new MyWindowListener(this));
    //=============================
    String[] laender = {"Deutscher", "Franzake", "Brite", "Ami", "Türke", "Inder", "Chinese", "Russe", "Spanier", "Kuba", "Afrikaner", "Italiener", "Joker"};
    String[] geschlecht = {"m", "w"};
    String[][] a = new String [2][(laender.length+1)*(geschlecht.length+1)*(4)];
    
    for(int k=0;k<4;k++)
    {
      for(int i=0; i<13; i++)
      { 
        for(int j=0; j<=1; j++)
        {
          a[0][(i+1)*(k+1)*(j+1)]=laender**;
          a[1][(i+1)*(k+1)*(j+1)]=geschlecht[j];
          //jListGastkarten.addElement(**[j]);
          jListGastkartenModel.addElement(laender**+" ; "+geschlecht[j]);
          restkartengast = restkartengast + 1;
          
        }
      }
    }
    jLabelRestkartenGast.setText("Restgäste: "+restkartengast);
    //Collections.shuffle(a[0]);
  }
  
  // Anfang Methoden
  
  // Ende Methoden
  
  public static void main(String[] args) {
    new CafeRoot("CafeRoot");
  } // end of main 
  public class MyWindowListener implements WindowListener {
    
    private CafeRoot cRoot;
    
    public MyWindowListener(CafeRoot cRoot) {
      this.cRoot = cRoot;
    }
    
    @Override
    public void windowActivated(WindowEvent arg0) { }
    
    @Override
    public void windowClosed(WindowEvent arg0) {
      cRoot.setVisible(false);  
    }
    
    @Override
    public void windowClosing(WindowEvent evt)
    {
      final JFrame Beenden = new JFrame("Ein Frame zum Schließen");
      Beenden.setTitle("Programm beenden");
      Object[] options = {"Ja", "Nein"};
      /*int beenden = JOptionPane.showConfirmDialog(null, 
      "Wollen Sie das Programm wirklich beenden?
Ihr Spielstand wird verloren gehen!",
      "Café International Beenden?",
      JOptionPane.WARNING_MESSAGE,
      JOptionPane.YES_NO_OPTION);*/
      int beenden = JOptionPane.showOptionDialog(null,
      "Wollen Sie das Programm wirklich beenden?
Ihr Spielstand wird verloren gehen!",
      "Café International Beenden?",
      JOptionPane.DEFAULT_OPTION, 
      JOptionPane.QUESTION_MESSAGE, 
      null, options, options[0]);
      if(beenden == 0)
      {
        //cRoot.dispose();
        System.exit(0);
      }
    }
    
    @Override
    public void windowDeactivated(WindowEvent arg0) { }
    @Override
    public void windowDeiconified(WindowEvent arg0) { }
    @Override
    public void windowIconified(WindowEvent arg0) { }
    @Override
    public void windowOpened(WindowEvent arg0) { }
    
    
  }
} // end of class CafeRoot

Ich hab bereits gelernt, dass man für meine Zwecke diesen Importbefehl oben mit einbauen muss:
import java.io.*;

Aber bisher waren mit die Quellen zu kompliziert. Kann mir jemand erklären, wie ich das machen soll und wo der dazu passende Code in meiner Datei reingehört?

Quellen waren bisher für mich:
Java, Werte aus .txt Datei nacheinander einlesen - ComputerBase Forum
Zahlen aus Textdatei lesen und in Konsole ausgeben
Integer aus Textdatei auslesen und in Variable speichern

Vielen Lieben Dank!
Gruß
Lukas

PS: Wenn jemand Zeit hat, wäre ich begeistert, wenn man dahinter kurz //kommentieren könnte, was wozu da ist. Ich möchte hier nicht einfach die “Copycat” spielen, die sich die Codes geben lässt aber keine Ahnung hat, wozu der da ist, dann präge ich mir das ja nie ein.

Um eine Textdatei einzulesen brauchst du bspw. einen [japi]InputStreamReader[/japi], der aus einem InputStream liest. Die Effizienz des Readers kann erhöht werden, wenn er gepuffert wird. Diese Funktionalität wird durch die Klasse [japi]BufferedReader[/japi] bereit gestellt.
Der Instanz des Readers wird also ein konketer InputStream zur Datenquelle übergeben. In deinem Fall ist die Datenquelle eine Datei, also brauchst du einen [japi]FileInputStream[/japi], der aus Dateien lesen kann. Da deine Datei nur aus Zeichenketten (Strings) besteht, kannst du den auf reine Textdateien spezialisierten [japi]FileReader[/japi], als Subklasse von FileInputStream, verwenden.

BufferedReader reader = new BufferedReader(new FileReader(...));```

Die Datei kann dann zeilenweise ausgelesen werden:
```//auslesen
String line = null;
while((line = reader.readLine) != null) {
   String[] keyValue = line.split(":");
   if(line.startsWith("punktespieler1")) {
      jLabelPunkteSpieler1.setText("Pkt. Spieler 1: "+keyValue[1]);
   }
   else if {
      ...
   }
}
reader.close();

Wenn du den Wert als int verarbeiten möchtest, muss er (keyValue[1]) noch entsprechend umgewandelt werden.
Und da dabei auch eine Menge schief gehen kann, muss das Ganze noch in einen try-catch-Block gepackt werden.

(Beitrag vom Verfasser gelöscht)

(Beitrag vom Verfasser gelöscht)

Hallo @FranzFerdinand ,

eine Fähigkeit, die man als Programmierer schnell lernen sollte ist, das Rad nicht nochmal zu erfinden.

Deine Datei hat den prinzipiellen Aufbau

schlüssel:wert

Zum Arbeiten mit solchen Dateien kennt Java bereits eine fertige Klasse: [JAPI]Properties[/JAPI]Mit dieser Klasse ändert sich Deine Zeile 37 in Post#3 zuReader reader =new BufferedReader(new FileReader("spielstand.txt")) Properties spielStand= new Properties(); try { spielStand.load(reader ); }catch(FileNotFoundException ex){ ex.printStactrace(); // kann ignoriert werden weil die Datei beim ersten Start noch nicht existiert. } reader.close();
Viel wichtiger ist aber die Änderung in den Zeilen 93 bis 102. Die schrumpfen nämlich zu einer einzigen Zeile:jLabelPunkteSpieler1.setText("Pkt. Spieler 1: "+spielStand.getProperty("punktespieler1"));
Aber die Klase kann noch mehr…
Wenn das Spiel das erste mal gestartet wird ist Deine Spielstand-Datei leer und der Schlüssel wird nicht gefunden. Für diesen Fall soll der Spielstand wahrscheinlich “0” sein. Anstatt jetzt groß überprüfungslogik selbst zu programmieren sagst Du das einfach der aufgerufenen Methode:jLabelPunkteSpieler1.setText("Pkt. Spieler 1: "+spielStand.getProperty("punktespieler1","0"));

Während des Spiels aktualisierst Du das Properties-Object zu passenden Gelegenheitet. Natürlich muss es dazu eine Objektvariable sein (die neue Zeile 38 muss vor den Konstruktor verschoben werden)spielStand.setProperty("punktespieler1",objectFuerSpieler1.getSpielstand());

Am Schluss musst Du den Stand dann noch speichern:spielStand.store(new FileWriter("spielstand.txt"),"wichtiger Kommentar");

bye
TT

(Beitrag vom Verfasser gelöscht)

Hallo @FranzFerdinand ,

wenn Du eh gerade am Umbauen bist lies don mal dies:
http://wiki.byte-welt.net/wiki/Warum_man_nicht_von_JFrame/JDialog_erben_sollte

bye
TT

(Beitrag vom Verfasser gelöscht)

Ich meine Zeile 15 in Post#1.
Deine Klase erbt von JFrame.
Vererbung ist eine ist ein-Bezieung. Dein Spiel soll aber einen JFrame haben.

Leider gibt es (zu) viele Beispiele im Netz die genau so aufgebaut sind.

bye
TT

[QUOTE=Timothy_Truckle;103925]Ich meine Zeile 15 in Post#1.
Deine Klase erbt von JFrame.
Vererbung ist eine ist ein-Bezieung. Dein Spiel soll aber einen JFrame haben.

Leider gibt es (zu) viele Beispiele im Netz die genau so aufgebaut sind.

bye
TT[/QUOTE]
Achso, hm, ja, ist im Status quo halt so. Vielen dank für den Hinweis, wenn ich mich mit Vererbung beschäftige ändere ich das.
Solange es keine Probleme macht, ist das jedoch keine Dringlichkeit.

Zu meinem anderen Problem zurück:

int variable1 = Integer.parseInt(string1);```

Ich arbeite immer noch an dem Problem, dass ich mit dem bisherigen Code zwar die Labels ausfülle, aber keine Variablen fülle. Der Text da oben läuft irgendwie nicht, wie er soll. Muss ich etwas spezielles beachten, was mir hier das Genick bricht?

[quote=FranzFerdinand]Der Text da oben läuft irgendwie nicht, wie er soll.[/quote]Bitte beschreibe dein Problem genauer:
[ul]
[li]wie genau weicht Dein Programm von Deiner Erwartung ab?
[/li][li]Gibt es eine Fehlermeldung vom Compiler? (Bitte posten)
[/li][li]Gibt es eine Fehlermeldung zur Laufzeit? (Bitte posten)
[/li][/ul]
bye
TT

(Beitrag vom Verfasser gelöscht)

Der normale Weg, sich wiederholenden Code einzusparen ist, eine Methode zu schreiben, die die sich wiederholenden Operationen aufnimmt: ```//…
int variable1=getIntAndSetLable(new JLable("Resttische: "),“restkartentisch”,“0”);
//…

// später in der Klasse
private int getIntAndSetLable(JLable lable, String key, String defaultValue){
String value = spielStand.getProperty(key, defaultValue);
lable.setTest(lable.getText()+value); // hier muss noch optimiert werden damit säter die values ersetzt und nicht alle einfach angehangen werden
return Integer.paseInt(value);
}```

bye
TT

(Beitrag vom Verfasser gelöscht)

Eintrag enthält bisschen wenig Infos,
gibt es unter den 100 auch Doppelte oder mindesten 50 verschiedene Länder + m/w?
wobei die Enum nicht viel erlaubt, dann wohl Doppelte,
na ist ja auch egal, kürzer gehts kaum, außer eben noch m/w als einzelne Buchstaben einzuführen,

wenn m/wm immer der erste Buchstabe ist könnte man dahinter Semikolon auch sparen usw., Spitzfindigkeiten

ob jeder Eintrag in einer Zeile oder noch ein Trennsymbol dazwischen ist beliebig (Zeilenumbruch ist auch ein Zeichen)

gastkarte vor jedem Eintrag, ob mit oder ohne Nummerierung, scheint überflüssig, falls nicht von anderen Einträgen zu unterscheiden ist,
Computer weiß die Nummerierung auch so, Textprogramme bei Zeilen ebenfalls, sonst für menschlichen Leser vielleicht noch hilfreich

am Anfang der Datei 1x gastkarte oder eine Kommentarzeile oder sonst irgendwas kann man machen oder auch ganz weglassen wenn z.B. Dateiname ausreicht,
alles ziemlich beliebig, da gibt es nicht viel zu empfehlen, jedenfalls keine wichtigen Best Practice


bei 100 Einträgen kann man auch die Datei immer komplett neu schreiben,
wenn es 50 MB wären schadet es nicht drauf zu achten, dass ein simples Hinzufügen eines neuen Eintrags möglich ist, wäre sparsam,
kann dann neben neuen Einträgen auch eine Info ‘Eintrag 45.678 ist eigentlich gelöscht’ sein statt ganze 50 MB ohne diesen Eintrag neu zu schreiben

deine Varianten erlauben das jeweils, aber wie gesagt auch nicht wichtig

Hallo und vielen Dank für Deine Antwort,

das soll eigentlich eine einzelne Speicherdatei sein, wie ich sie eingangs des gesamten Themas hier erstellt habe. Keine neue Extradatei. Eine einzige Textdatei, die den gesamten Speicherstand notiert.
Es handelt sich um 13 Länder und 2 Geschlechter, die in Einzelkombination je 4 mal auftreten. 2134= 104 (Es gibt nur 2 statt 4 Joker) -> 100 Karten sind das.

Die werden, wie man im Code sieht in eine List gemischt und dann in die jList eingefügt. Und diese würde ich gerne in die Speicherdatei reinschreiben und wieder auslesen.

Gruß
Lukas

Wenn es ein festes Set an Karten gibt würde ich die programmatisch erzeugen und nicht aus einer Datei lesen.

bye
TT

(Beitrag vom Verfasser gelöscht)

Ein mögliche Alternative - sobald etwas mehr Programmiererfahrung und Kenntnisse der Objektorientierung vorliegen - könnte die Serialisierung sein. Wenn Du ein Model verwendest in dem der Spielstand verwaltet wird, könnte man dieses Objekt einfach in eine Datei serialisieren und bei Bedarf wieder deserialisieren.

In deinem Fall, auch da die Daten nicht sonderlich komplex sind ist es aber vermutlich geschickter diese selbst in eine Datei zu schreiben und da ist es egal, ob alles in eine Zeile oder eine Zeile pro Info.
Evtl. könnte man das auch gleich in Form eines xmls machen, dann wäre es m.M. etwas besser lesbar - falls das überhaupt gewünscht ist.

die Keys in Properties müssen unique sein,
wenn das dein Ziel ist, dann bietet sich Nummerierung an

        throws Exception
    {
        FileInputStream in = new FileInputStream("spielstand.txt");
        Properties spielstand = new Properties();
        spielstand.load(in);
        for (int n = 0; n < 20; n++)
        {
            spielstand.setProperty("gastkarten" + n, "lalelu" + (n % 5));
        }
        spielstand.store(new FileOutputStream("spielstand.txt"), "Gespeichertes Spiel");
    }

erzeugt/ füllt bei mir Textdatei


#Gespeichertes Spiel
#Fri Oct 31 11:52:41 CET 2014
gastkarten12=lalelu2
gastkarten11=lalelu1
gastkarten10=lalelu0
gastkarten9=lalelu4
gastkarten8=lalelu3
gastkarten7=lalelu2
gastkarten6=lalelu1
gastkarten5=lalelu0
gastkarten4=lalelu4
gastkarten3=lalelu3
gastkarten2=lalelu2
gastkarten1=lalelu1
gastkarten0=lalelu0
gastkarten19=lalelu4
gastkarten18=lalelu3
gastkarten17=lalelu2
gastkarten16=lalelu1
gastkarten15=lalelu0
gastkarten14=lalelu4
gastkarten13=lalelu3

nicht gerade sortiert, aber muss ja auch nicht sein,
Einlesen ebenso mit Schleife, genaue Keys zusammenbauen

ich habe bisschen älteres Java 1.5, da mit Stream statt Reader/ Writer

wenn du dich auch Properties-Format verläßt, dann sollte das zumindest zwischen zwei Properties kaum ein Problem sein, siehe mein Beispiel/ deine Dateien