Autor Beitrag
Terrenay
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Fr 31.01.14 23:20 
Erstmal vorweg, ich bin erst 13 und programmiere noch nicht sehr lange, also nehmt es mir bitte nicht übel, wenn diese Frage einfach zu beantworten sein sollte ;)

Ich habe in der letzten Woche ein klitzekleines Kampfspiel, ähnlich wie Pokemon programmiert, und darin geht es halt darum, möglichst viele Runden zu überleben.
Jetzt möchte ich, dass beim Beenden des Programms die aktuelle Runde in eine Datei geschrieben wird, und beim nächsten Start in etwa so ausgegeben wird: "Willkommen zurück! Dein bisheriger Highscore liegt bei Runde SoUndSo".

Aber ich weiss nicht, wie genau ich das machen soll :(
Im Moment habe ich es einfach so implementiert, dass die erreichte Runde des letzten Spiels ausgegeben wird.
Das sieht so aus:

Bei Aufruf des FormLoad-Events:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
StreamReader sr = new StreamReader("NexusHighscore.txt");
            int Highscore = int.Parse(sr.ReadToEnd());
            if (File.Exists("NexusHighscore.txt"))
            {
                MessageBox.Show("Willkommen zurück! \r\nAls du das letzte Mal gespielt hast, hast du folgende Runde erreicht: " + Highscore, "Willkommen Zurück!");
            }
            sr.Close();


Bei Aufruf des FormClosing-Events:
ausblenden C#-Quelltext
1:
2:
3:
4:
StreamWriter sw = new StreamWriter("NexusHighscore.txt");
            sw.WriteLine(Variablen.Runde);
            sw.Flush();
            sw.Close();



Bei diesem Code bekomme ich übrigens auch einen Fehler, aber nur, wenn ich das Programm zum ersten Mal starte, sprich, die Datei "NexusHighscore.txt" noch nicht vorhanden ist. Aber ich habe doch mit File.Exists getestet, ob die Datei vorhanden ist?!

Kann mir bitte jemand helfen? :)

Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Fr 31.01.14 23:41 
Hallo und :welcome:!

Das sieht ja schon mal nicht schlecht aus :)

Der Grund, warum die Fehlermeldung bekommst, ist, weil Du die Existenz der Datei erst prüfst, nachdem Du versucht hast, daraus zu lesen. Lesen tust Du ja hier
ausblenden C#-Quelltext
1:
2:
StreamReader sr = new StreamReader("NexusHighscore.txt");
int Highscore = int.Parse(sr.ReadToEnd());

und die Prüfung kommt erst später.

Das heißt, die if-Abfrage für die Prüfung der Existenz der Datei muss um alles herum, was auf diese Datei angewiesen ist:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
if (File.Exists("NexusHighscore.txt"))
{
    StreamReader sr = new StreamReader("NexusHighscore.txt");
    int Highscore = int.Parse(sr.ReadToEnd());
    sr.Close();
    MessageBox.Show("Willkommen zurück! \r\nAls du das letzte Mal gespielt hast, hast du folgende Runde erreicht: " + Highscore, "Willkommen Zurück!");
}

Wie Du siehst, habe ich auch das Schließen des Streams ein wenig vorgezogen, weil es keinen Grund gibt, den noch länger offen zu halten.




Nun noch zwei Dinge, die man IMHO verbessern sollte.

Zuerst einmal: Du gibst bei der Datei kein Verzeichnis an, das heißt es wird das "aktuelle" Verzeichnis benutzt. Zum einen ist das nicht immer so definiert, wie man das gerne hätte, zum anderen ist es meistens das Verzeichnis, in dem die Anwendung liegt. In den meisten Windows-Versionen hat man dazu aber keinen Schreibzugriff. Ich würde die Datei daher in das Benutzerverzeichnis schreiben:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
      var folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Dein Name""Name Deiner Anwendung");
      if (!Directory.Exists(folderPath)) //Verzeichnis erstellen, wenn es nicht existiert
        Directory.CreateDirectory(folderPath);

      var filePath = Path.Combine(folderPath, "NexusHighscore.txt");


Und dann, das ist das die zweite Sache, würde ich den Zugriff auf die Datei so absichern, dass die entsprechenden Systemresourcen immer freigegeben werden, auch wenn ein Fehler passiert. Das macht man am Besten über die using-Anweisung:
ausblenden C#-Quelltext
1:
2:
      using (StreamWriter sw = new StreamWriter(filePath))
        sw.Write(Variablen.Runde);

Die sorgt automatisch dafür, dass auch im Fehlerfall die Resourcen freigegeben werden und im "Normalfall" übernimmt sie auch das Schließen des Streams für einen.


Ich hoffe, das hilft schon mal weiter, ansonsten einfach fragen :)

Viele Grüße
Christian

P.S.: Das man das Verzeichnis erstellt, macht natürlich nur Sinn, wenn man Reinschreiben will. Wenn man nur lesen will, reicht es, zu schauen, ob die Datei existiert.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".

Für diesen Beitrag haben gedankt: FinnO, Terrenay
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Sa 01.02.14 02:56 
Du kannst dir auch mal die Methode File.ReadAllLines anschauen. Da sparst du dir das Ganze drum herum und bekommst direkt alle Zeilen aus der Datei gelesen.
Prüfen, ob die Datei/das Verzeichnis existiert, musst du aber trotzdem.

Oder File.ReadAllText, ach was, schau dir einfach die ganze File-Klasse an :D
Für einfache Arbeiten mit Dateien bringt die eigentlich alles Nötige mit und du musst dich gar nicht selber um das Öffnen und Schließen der Datei kümmern.

Moderiert von user profile iconTh69: C#-Tags hinzugefügt

Für diesen Beitrag haben gedankt: Terrenay
Terrenay Threadstarter
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Sa 01.02.14 10:55 
Danke für die Antworten :) werds nachher gleich mal ausprobieren!
Etwas wichtiges habe ich leider vergessen zu erwähnen: Eigentlich möchte ich nicht, dass es einfach die letzte erreichte Runde ausgibt, sondern die höchste, die jemals erreicht wurde!

Als ich das einmal ausprobiert habe, bekam ich aber jedes zweite Mal eine exception und in den anderen fällen einfach die letzte erreichte runde :(
Versteht ihr, was ich meine?


@Christian: Und wie mache ich das dann, wenn ich das Programm zB einem Freund zum downloaden geben will? Dann ändert sich ja der Name des Benutzers ^^



EDIT: Habs geschafft, dass es den Highscore speichert :D Danke Palladin007 für den Tipp mit den File.-Befehlen :)
Danke auch @Christian, für die Prüfung, ob die Datei existiert ^^ Funktioniert soweit einwandfrei, allerdings ist immer noch die Frage offen, wie der Pfad dann auch für einen anderen Benutzer gültig ist... Kann mir da vielleicht auch noch jemand helfen? :)

So hab ich den Highscore jetzt gespeichert:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
try
{
   string x = File.ReadAllText("NexusHighscore.txt").ToString();
   int y = int.Parse(x);

   if (Variablen.Runde > y) //Wenn ein neuer Highscore vorliegt
      File.WriteAllText("NexusHighscore.txt", Variablen.Runde.ToString()); //Speichere die Runde in die Datei
}
catch //Wenn die Datei noch nicht existiert oder leer ist
{
   File.WriteAllText("NexusHighscore.txt", Variablen.Runde.ToString()); //Speichere die Runde auch in die Datei
}
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4807
Erhaltene Danke: 1061

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 01.02.14 12:52 
Hallo Terrenay,

das ApplicationData-Verzeichnis ist schon benutzergebunden (s. Environment.SpecialFolder-Enumeration), d.h. es reicht einfach
ausblenden C#-Quelltext
1:
var folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Name Deiner Anwendung");					

Für diesen Beitrag haben gedankt: Terrenay
Terrenay Threadstarter
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Sa 01.02.14 13:05 
Vielen Dank, hat sofort funktioniert :)

Damit wären auch schon alle meine Fragen geklärt :D
Danke für eure Zeit ^^

Moderiert von user profile iconTh69: Vollzitat entfernt.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 01.02.14 13:43 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Terrenay,

das ApplicationData-Verzeichnis ist schon benutzergebunden (s. Environment.SpecialFolder-Enumeration), d.h. es reicht einfach
ausblenden C#-Quelltext
1:
var folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Name Deiner Anwendung");					

Es ist üblich, dass man in ApplicationData nicht direkt den Ordner fürs Programm legt, sondern erst einen Ordner des Herausgebers (z.B. "Microsoft" oder in diesem Fall der Name des Programmierers) und darin der Ordner für die Anwendung. Daher stand dort "Dein Name", nicht als Name des Benutzers, sondern als Name des Programmierers.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".

Für diesen Beitrag haben gedankt: Terrenay
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4807
Erhaltene Danke: 1061

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 01.02.14 18:44 
Hallo Christian,

ach so meintest du das. ;-)
Ich habe gerade mal bei mir nachgeschaut: das machen aber meist nur die großen Firmen (Microsoft, Adobe, Mozilla), andere Programme nur direkt mit dem Programmnamen (VLC, FreeDoko). Aber es macht ja auch Sinn, wenn man mehrere Programme anbietet, diese in einen eigenen Unterordner zu stecken.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Sa 01.02.14 19:04 
Das ist die Microsoft Empfehlung ich selbst würde es nicht (mehr) so machen . Diese Company/Product Struktur ist eine doppelte Sollbruchstelle beim updaten.

Der arme Entwickler tut mir Leid der zum Beispiel das Upgrade Setup für Delphi schreibt. Der müsste, wenn die sich dran halten, im Borland/Inprise/Codegear/Embarcadero Ordner den entsprechenden Anwendungsunterordner (wenn sich der auch mal geändert hat) nach alten Einstellungen/Setups suchen . Wenn es mal ein Wechsel von x86 nach x64 geben sollte dann auch noch in den zwei verschiedenen Programme-Ordnern. Statisch gesehen ist die Company/Product Empfehlung nett sowohl im Filesystem also auch in der Registry. Bei Software mit Historie eine Bestrafung. Ich glaube Microsoft empfiehlt sogar das neben Company/Product auch die Versionsnummer der Anwendung da mit aufzunehmen ist (zumindest bei user Settings macht das ja .Net automatisch). Eindeutig Empfehlungen eines Unternehmens das jedes Problem mit Manpower erschlagen kann.