Java - Problem beim Lesen/schreiben in eine Datei?

4 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Ich habe dir bereits in der anderen Antwort gesagt, dass die Zeile mit dem FileOutputStream so nicht stimmt. Ich finde es schade, dass Du Dich nicht bemühst selber die Lösung zu finden, schließlich habe ich dir in der von Dir zuvor gestellten Frage einige Tipps gegeben.

So wirst du das Programmieren nicht lernen. Es bringt nichts, wenn Du hier eine Lösung in deinem Programm nutzt, diese aber nicht verstanden hast.

String str = "Hallo Welt";
File file = null; // hier file Objekt erstellen mit FileChooser

// check file obj to prevent nullptr
if (file == null)
  // statt throw ... hier dein ExceptionHandling ergaenzen
  throw new IllegalStateException("File does not exist.");

// append file ext
if (! file.getAbsolutePath().endsWith(".edit"))
  file = new File(file.getAbsolutePath() + ".edit");

// write str to file
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
  bw.write(str);
} catch (IOException e) {
  throw new RuntimeException(e);
}
Woher ich das weiß:Studium / Ausbildung
Anonymer4User 
Fragesteller
 02.01.2019, 15:36

Das ist so zwar nicht ganz richtig, aber trotzdem Danke für deine Hilfe.

0
Anonymer4User 
Fragesteller
 02.01.2019, 16:57
@milos2

Ich habe mich schon bemüht, aber wenn ich nicht weiter weiß, was soll ich machen?

0
milos2  02.01.2019, 15:39

Noch eine Ergänzung zur Antwort: Das Encoding wird in dem Beispiel nicht berücksichtigt. Wenn du das hier verstanden hast, solltest Du dich als nächstes damit beschäftigen.

0
Anonymer4User 
Fragesteller
 02.01.2019, 17:03

Ok funktioniert nun, vielen Dank

0
  1. Prüf immer, ob die Datei-Endung schon dran hängt, bevor Du sie ergänzt, sonst hast Du irgendwann "myFile.edit.edit.edit.edit".
  2. Ein Stream (und auch der Reader/Writer dazu, wenn es Einen gibt) sollte immer geschlossen (Close-Methode) werden, sowohl im Erfolgsfall als auch im Fehlerfall. Im zweiten Code-Schnipsel wird das gemacht.
  3. Verwende keine unnötigen Abkürzungen, außer sie sind in der Community weit verbreitet. "fil" ist mMn. unnötig, anhand "s" kann niemand erkennen, was das nun sein soll - ich hätte z.B. an einen String gedacht und nicht an Scanner.

Ich würde bei dir darauf tippen, dass der Stream nicht geschlossen wird, denn das sorgt intern dafür, dass die Datei tatsächlich geschrieben wird (Stichwort: Flush). Normalerweise teilt Java (und auch andere Frameworks) dem Windows nur mit, es soll "XYZ" in besagte Datei schreiben. Windows entscheidet dann selber, wann es das tut und im Extremfall tut es das eben gar nicht - bis das Programm explizit sagt, es soll JETZT schreiben.

Das könnte erklären, warum die Datei leer ist. Es könnte auch erklären, warum Du nicht darauf zugreifen kannst, denn Windows blockiert die Datei für Lese- und Schreib-Zugriffe (kann man einstellen), wenn das Programm damit noch arbeitet. Wenn der Stream korrekt geschlossen wird, wird auch diese Blockade entfernt.

PS:
Ich kann nicht garantieren, dass meine Erklärung 100% stimmt, da ich selber nicht mit Java arbeite. Da allerdings die wichtigsten Inhalte von Java den anderen Frameworks (in meinem Fall .NET von Microsoft) sehr ähnlich sind, gehe ich davon aus, dass auch hier alles gleich ist. Abgesehen davon ist egal, wie die Frameworks arbeiten, Windows arbeitet in beiden Fällen gleich ^^

milos2  02.01.2019, 15:36
Verwende keine unnötigen Abkürzungen, außer sie sind in der Community weit verbreitet. "fil" ist mMn. unnötig, anhand "s" kann niemand erkennen, was das nun sein soll - ich hätte z.B. an einen String gedacht und nicht an Scanner.

Exakt. Scanner wird immer mit sc abgekürzt. File würde ich file nennen und nicht fil. Und der BufferedWriter heißt bw und nicht wrt.

0
Palladin007  02.01.2019, 15:58
@milos2

Das ist dann wohl eine Grundsatzdiskussion ;) Scanner hätte ich z.B. einfach "scanner" genannt (vielleicht mit einem Zusatz, was genau für ein Text gelesen werden soll. Der Verlust beschränkt sich auf ein paar Zeichen mehr und später kann die IntelliSense (gibt's sowas bei Eclipse?) sehr, sehr viel von dieser Schreibarbeit abnehmen. Der Gewinn ist aber, dass man irgendwo im Code eine Zeile (im Idealfall) auf Anhieb versteht und nicht erst gucken muss, was der Typ der Variable ist oder in welchem Kontext sie erstellt wurde.

Meiner Meinung nach sind alle Abkürzungen für Worte mit weniger als 10 Zeichen (Pi Mal Daumen) völlig unnötig und zu unterlassen. Für sehr lange, zusammengesetzte Namen würde ich erst Mal überlegen, ob man das nicht verkürzen kann, ohne den Informationsgehalt zu drastisch einzuschränken. Häufig lasse ich Teile des Namens weg (AuftragsPosition wird zu Position), wenn eindeutig klar ist, in welchem Kontext ich mich befinde. Ich würde das aber nicht "pos" nennen. Das schöne an guten Namen ist, dass sauber geschriebener Code sich mit etwas Fantasie wie ein normaler Text lesen lässt - was definitiv vorteilhaft für die Lesbarkeit und das Verständnis ist.

BufferedWriter hätte ich da einfach nur "writer" genannt. Wenn die Methode (und das sollte sie) unabhängig von den restlichen Funktionen nur das stumpfe Schreiben von Text in eine Datei übernimmt, ist ja sowieso klar, dass da in eine Datei geschrieben werden soll, also kann die Info weg fallen. Und da die Methode nicht weiß, was sie schreibt, kann das auch weg fallen.

Ob die Abkürzungen immer so sind, wie Du sagst, weiß ich nicht, da ich selber nicht mit Java arbeite, allerdings würde ich mich da am ehesten nach Foren richten. Wenn überall so abgekürzt wird, ok, wenn nicht, würde ich das auch nicht tun. Bei Microsoft gibt's dafür Guidelines und an die halten sich glücklicherweise auch sehr viele Entwickler.

Ich arbeite nicht so, weil ich ständig meinen Code online poste, sondern weil mit Abkürzungen auch Gewohnheiten einhergehen. Anderen Kollegen fällt es genauso leichter, meinen Code zu verstehen, wie auch potentiellen Helfern. Umgekehrt kann ich den Code von Anderen leichter verstehen. In einer Community oder einem Team steht und fällt viele mit einer einheitlichen Nomenklatur und dem Stil, wie der Code geschrieben wird. Arbeiten alle ähnlich, fällt es jedem leicht(er), sich in den Code des Anderen einzuarbeiten - oder es wird überhaupt erst möglich, fremden Code in zumutbarer Zeit zu verstehen.

1
milos2  02.01.2019, 16:13
@Palladin007
Ich würde das aber nicht "pos" nennen.

Ich schon. Denn das ist eine gängige Bezeichnung.

Die Meinungen gehen aber auseinander. Es hängt aus meiner Sicht von der Lebensdauer der Variable ab. Je kürzer die Dauer, desto kürzer der Name. Bei for Schleifen gibt es eine Variable nur für einen kurzen Moment. Die heißt dann oftmals einfach nur i (also ein Buchstabe). In diesem Kontext ist die Lebensdauer der Streams auch stark begrenzt, daher würde ich allerhöchstens drei Buchstaben, besser zwei, opfern.

Ob die Abkürzungen immer so sind, wie Du sagst, weiß ich nicht, da ich selber nicht mit Java arbeite, allerdings würde ich mich da am ehesten nach Foren richten.

Aus meiner Sicht gibt es eben verbreitete Abkürzungen. Wie Du bereits erwähnt hast:

  • pos --> position
  • ln/len --> length
  • ch --> char
  • n --> number
  • elm -> element

Und wenn man diese gängigen Abkürzungen nutzt, kann man gute Namen für Variablen verwenden, bspw. für die Anzahl von Wörtern:

  • nword (würde ich schreiben)
  • numWords
  • numOfWords
  • numberOfWords
  • thisVariableStoresTheNumberOfTheWords
0
Palladin007  02.01.2019, 16:43
@milos2
Es hängt aus meiner Sicht von der Lebensdauer der Variable ab. Je kürzer die Dauer, desto kürzer der Name. Bei for Schleifen gibt es eine Variable nur für einen kurzen Moment.

Da muss ich dir Recht geben, das habe ich vorhin außer Acht gelassen.

Allerdings kommt es leider viel zu oft vor, dass aus einer vermeindlich kurzen Lebensdauer eine sehr große Lebensdauer wird. Über Jahre hinweg wird der Code immer mehr erweitert und aus 3 Zeilen werden 30 Zeilen. Oder man lässt sich automatisch Methoden generieren bzw. Code in Methoden auslagern (VisualStudio kann das) und führt dann diese Namen in anderen Methoden fort. Oder noch extremer: Variablen werden aus irgendwelchen Gründen in Klassen ausgelagert und so ziehen sich die Variablen für einen kleinen Bereich nach und nach durch das ganze Programm.

Mir ist klar, dass bei solchen Extrem-Beispielen (die sind hier mein täglich Brot) schon vorher so Einiges schief gelaufen ist, aber man kann sie vermeiden, wenn man von Anfang an eine einheitliche Nomenklatur verwendet. Dank moderner IDEs kostet das auch kaum mehr Zeit, da die IDE sowohl das Suchen als auch das Schreiben (Autovervollständigung) übernimmt.

Die Nachteile, auf solche Abkürzungen zu verzichten sind daher eher gering.
Allerdings verwende auch ich häufig Ein-Zeichen-Namen oder extrem kurze Abkürzungen, allerdings hauptsächlich in sehr kurzen Lambda-Expressions. Sobald es da um mehrere Zeilen geht, wähle ich auch einen langen Namen.

Für dein Beispiel hätte ich "wordsCount" verwendet, das ist kurz und sofort klar, was gemeint ist. Das allerdings hauptsächlich, da es in .NET für alles, was irgendwie eine Auflistung sein kann, eine "Count"-Methode existiert.

In manchen Fällen, wie z.B. bei der Länge eines Arrays lagere ich das manchmal gar nicht in eine Variable, sondern verwende den Aufruf einfach mehrfach. Der Vorteil ist aber, dass man eine Variable weniger hat, deren Name vermutlich kaum kürzer oder sogar länger wäre, als der Aufruf selber. Die Performance ist zu vernachlässigen, den Verlust kann man wahrscheinlich nicht Mal messen, wenn es überhaupt einen Unterschied gibt.

0
regex9  02.01.2019, 18:12
@Palladin007

Der Bezeichner sollte den Namen bekommen, der am eindeutigsten ausdrückt, was die Variable / Funktion / ... tut. So wirklich gängige Bezeichner, die mir bisher untergekommen sind, wären i bei Schleifen, ex (Exception) und e / evt (für Event in Skriptsprachen). Doch sie missachten eigentlich auch schon die Regel und bergen Probleme. So schreiben manche wiederum für Exceptions nur e.

Bei Lambdas halte ich es z.T. noch für verständlich. Grundsätzlich von der Lebensdauer einer Variable würde ich die Länge des Bezeichners jedoch keinesfalls abhängig machen. Selbst wenn diese kurz ist, kann die Variable in einem schwer verständlichen Kontext stehen. Und wie du es selbst schon geschrieben hast - der Code wächst.

0
Palladin007  02.01.2019, 18:57
@regex9

Die Kürzel i, ex, etc. kenne ich auch. Die finde ich dann auch wieder in Ordnung, da sie praktisch überall (in vielen Sprachen) verwendet werden und IDEs (z.B. VisualStudio) die so automatisch generieren. Sie sollten aber auch nur in diesem Kontext verwendet werden, sprich: i bleibt immer und überall ein Index, ex bleibt immer und überall eine Exception, etc. Diese Kürzel verwende ich aber auch nur dann, wenn die Lebensdauer der Variable kurz bleibt, ein Methoden-Parameter wird bei mir nie so einen Namen haben, den schreibe ich dann wiederum aus.

Meiner Meinung nach sollte bei langem Schleifen-Inhalt eben dieser Inhalt nach Möglichkeit in einer eigenen Methode landen - zumindest wenn die Methode ansonsten länger ist, als der Bildschirm lang ist. Das macht es 1. lesbarer und zwingt 2. dazu, den Inhalt zu separieren, bzw. auf das Single Responsibility Principle zu achten. In langen Methoden geht das sehr schnell verloren.

Das hängt auch vom Lambda ab. Manchmal schreibe ich den Code bewusst in mehrere Zeilen, damit es mehr heraus sticht und die Zeile kürzer wird. Dann lohnt sich auch wieder ein längerer Variablen-Name.

1
regex9  02.01.2019, 19:05
@Palladin007

Sehe ich genauso. Durch Auslagerung kann man Bezeichner evt. kürzen (Abkürzungen wie num oder pos würde ich dennoch weiterhin meiden), stimmt.

0

output.toString() gibt nur die Adresse des Objekts zurück. Du willst den Pfad.

file = new File(path);

BufferedWriter wrt = new BufferedWriter(new FileWriter(file));
wrt.write(gui.text.getText());
wrt.close();

Ich würde den kompletten Teil mit dem FileOutputStream weglassen.

Hast du schonmal geguckt, ob dein FileChooser auch richtig funktioniert?

Woher ich das weiß:Berufserfahrung – Softwareentwicklerin
Anonymer4User 
Fragesteller
 02.01.2019, 14:29

Aber ich möchte ja eine andere Dateiendung, die ich dann wiederum nicht hätte.

0
Lamanini  02.01.2019, 15:00
@Anonymer4User

Den neuen Namen zu bestimmen soll nicht das Problem sein. Ich würde einen neuen Pfad so bestimmen:

static String newName(String path, String newEnding) {
		int index = path.lastIndexOf(".");
		
		String name = path.substring(0, index);
		
		String newPath = name + newEnding;
		
		return newPath;
	}

Du gibst dieser Funktion einen Dateipfad, und diese gibt den neuen Pfad mit einer ausgewählten Endung zurück.

0
milos2  02.01.2019, 15:38
@Anonymer4User

Ja, aber dazu nutzt man keinen FileOutputStream. Beschäftige dich endlich mit den IO Streams. Das habe ich bereits in der anderen Frage als Antwort geschrieben. Du verwendest hier nämlich einfach irgendwas, ohne den Sinn dahinter verstanden zu haben. Du brauchst an der Stelle ein File Objekt, überprüfst die Endung, wenn es keine gibt, erstellst Du ein neues File Objekt.

0

1.) Macht es nicht Sinn im oberen Beispiel erst die vorherige Dateiendung vor dem setzen der neuen zu entfernen?

2.) Was für eine Errormeldung bekommst du den beim ersten?

3.) Kannst du die Datei test.edit manuell in einem Texteditor öffnen?

Destranix  02.01.2019, 14:12

Lese gerade, dass da steht "Keine Errormeldung..."

Muss kurz denken...

0
Destranix  02.01.2019, 14:13
@Destranix

Hast du schon versucht den Pfad manuell auf "test.edit" zu setzen und nicht über die Methoden?

0