Java Daten nicht untereinander sondern nebeneinander ausgeben?
Hallo Leute!
Ich habe von meinem Lehrer die Aufgabe bekommen, mit Java Punkte vom Lorenzmodell auszurechnen und die Daten (drei Koordinaten) in einer txt-Datei abzuspeichern. So weit bin ich gekommen:
public class Lorenzmodell {
public static void main(String[] args) {
// TODO Auto-generated method stub
double x = 0.1;
double y = 0;
double z = 0;
double a = 10.0;
double b = 28.0;
double c = 8.0 / 3.0;
double t = 0.01;
int n = 1000;
int i;
for ( i = 0; i < n; i++ ){
double xt = x + t * a * (y - x);
double yt = y + t * (x * (b - z) - y);
double zt = z + t * (x * y - c * z);
x = xt;
y = yt;
z = zt;
System.out.println(x);
System.out.println(y);
System.out.println(z);
}
}
}
Mein Problem ist jetzt, dass die Daten untereinander ausgegeben werden ich aber möchte, dass alle Werte in einer Art Tabelle rausgegeben werden. Also alle Werte für x in einer Zeile , für y und für z. Könntet ihr mir da weiter helfen?
Außerdem verstehe ich nicht was mein Lehrer mit der Text-Datei meinte. Ist es das mit dem Ausgeben also das mit system.out.println was er gemeint hat?
Wundert euch bitte nicht, dass ich so wenig Ahnung habe, unser Lehrer erklärt uns fast nichts und wir müssen alles dauernd selber recherchieren und ich habe bis jetzt noch nichts mit Java gemacht.
7 Antworten
Das Wesentliche wurde schon in anderen Antworten gesagt. Ich versuche es mal etwas ausführlicher und mit etwas einfacheren Worten.
Außerdem gehe ich beim Beispiel schrittweise vor, etwa so, wie ich es in der Praxis auch tue, wenn ich nicht alles gründlich vorher geplant habe. (Und auch dann fehlen immer ein paar Teile, die man später einfügen muss.)
-----
Wie schon gesagt, "println" steht für "print line", also "schreibe Zeile". Die "Methode" println setzt also nach ihre Ausgabe einen Zeilenumbruch.
Die Methode "print" funktioniert ganz genauso wie die Methode "println", nur dass sie keinen Zeilenumbruch anhängt. Du musst dich also selbst darum kümmern, ein Trennzeichen einzufügen. Meistens nimmt man ein Leerzeichen, ein Semikolon, ein Komma oder ein Tabulatorzeichen.
Ach ja, einen Unterschied gibt es noch zwischen print und println: du kannst "println()" ohne "Argumente" aufrufen, dann wird nur ein Zeilenumbruch eingefügt. Bei "print()" macht der Compiler nicht mehr mit -- das wäre ja auch sinnlos, hier würde gar nichts ausgegeben werden.
D. h. statt
System.out.println(x);
System.out.println(y);
System.out.println(z);
schreibst du z. B.
System.out.print(x); System.out.print("\t");
System.out.print(y); System.out.print("\t");
System.out.print(z); System.out.println();
("\t" steht hier für das Tabulatorzeichen -- das kannst du ggf. durch ein anderes Trennzeichen ersetzen.)
-----
Thema 2: die Textdateien.
Sicher hast du schon einmal mit Word oder einem anderen Textverarbeitungsprogramm gearbeitet und Texte abgespeichert. Abgespeichert werden solche Texte in "Dateien".
Irgendwie muss so ein Programm wie Word seine Texte in die Datei hineinkriegen, und ihr sollt lernen, wie so etwas (im Prinzip) funktioniert.
Bis jetzt habt ihr System.out verwendet, um Ausgaben zu erzeugen. System.out schreibt in eine sogenannte Konsole, die ihr euch direkt anschauen könnt.
Der Programmiersprache Java selbst ist es egal, wohin etwas geschrieben wird, dafür sorgt der "Stream" ("Datenstrom") System.out -- der weiß, wie man Text in die Konsole schreibt.
Es gibt aber noch andere Streams, z. B. solche, die Texte in Dateien schreiben (so was brauchen wir hier), solche, die Anfragen ins Internet schicken, solche, die Webseiten aus dem Internet empfangen, solche, die Klänge oder Filme übertragen ("Audiostreams", "Videostreams" -- daher das Wort "streamen") und viele andere.
Kommen wir zu einem Beispiel. Da es erst einmal darum geht, die Grundlagen zu verstehen, kümmere ich mich hier nicht um "Ausnahmen", mit denen man beim Lesen und noch mehr beim Schreiben von Dateien immer rechnen muss. D. h. ich würde es gern tun, aber der Java-Compiler mag das gar nicht.
Versuchen wir, den Stream zu erzeugen, der in die Datei schreibt, statt in die Konsole:
FileWriter outToFile = new FileWriter("Lorenz.txt");
Erst einmal meckert der Compiler, weil er FileWriter nicht kenn. Eclipse schlägt vor, die nötigen import-Anweisungen einzutragen, wir können aber auch von Hand an den Dateianfang schreiben:
import java.io.FileWriter;
import java.io.IOException;
Leider funktioniert das auch damit immer noch nicht (wie schon oben gesagt) -- der Compiler meckert, weil bei "new FileWriter(...)" eine Ausnahme auftreten kann, z. B. wenn die Datei schon existiert und schreibgeschützt ist.
Also nehme ich den Vorschlag von Eclipse an, da einen try-Block drumzusetzen:
try {
FileWriter outToFile = new FileWriter("Lorenz.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Es fehlt aber noch etwas sehr wichtiges: eine Datei, in die geschrieben wird, ist gesperrt, damit nicht ein anderer Prozess gleichzeitig mitmischt und alles durcheinander bringt. Wir müssen dem Dateisystem also mitteilen, dass die Datei wieder freigegeben werden soll.
Dafür hat der FileWriter die Methode close().
Damit sie auf jeden Fall aufgerufen wird, egal, was zwischendurch schiefgeht, müssen wir an den try-Block noch ein finally anhängen:
try {
FileWriter outToFile = new FileWriter("Lorenz.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
outToFile.close();
}
(Euer Lehrer hat euch doch sicher schon try...catch...finally beigebracht? Wenn nicht, wäre das unverantwortlich, weil man ohne dies mit Java keine sinnvolle Datei-Ein- und -Ausgabe hinkriegt.)
Und wir kriegen schon die nächste Compilerbeschwerde. Diesmal, weil er outToFile angeblich nicht kennt. Immerhin kann man das verstehen, weil die Variable nur im try-Block bekannt ist, aber nicht in den logisch eigentlich dazugehörigen catch- und finally-Blöcken. Nun ja, wir sind weniger stur als der Compiler und definieren die Variable vor dem try-Block:
FileWriter outToFile;
try {
outToFile = new FileWriter("Lorenz.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
outToFile.close();
}
Hä? Was sagt der Compiler diesmal? outToFile ist nicht initialisiert? Ach ja, das kann ja auch noch passieren, dass schon bei new FileWriter ein Fehler auftritt und dann bleibt outToFile "uninitialisiert". Eigentlich sollte da von Anfang an null drin stehen, und das tut es auch, aber hier weiß beim Compiler die linke Hand nicht, was die rechte tut. Also die nächste Ergänzung:
FileWriter outToFile = null;
try {
outToFile = new FileWriter("Lorenz.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
outToFile.close();
}
Und -- inzwischen überrascht es uns nicht mehr -- wieder beschwert sich der Compiler. Was hat er denn diesmal? Ach so, die close-Methode kann ja auch wieder zu einer "Ausnahme" führen. Seufz. Also setzen wir hier auch einen try-Block drum. Eclipse ergänzt das zu:
try {
FileWriter outToFile = new FileWriter("Lorenz.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
outToFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Diesmal dürfen wir ein wenig überrascht sein, denn der Compiler motzt diesmal nicht.
Lassen wir das Ding mal laufen und schauen in den Projekt-Ordner. Hier finden wir jetzt eine Datei "Lorenz.txt". Die ist zwar noch leer, aber immerhin haben wir es geschafft, überhaupt eine Datei anzulegen.
Der Rest sollte jetzt nicht mehr allzu schwer sein -- wir füllen die Datei mit Text. Probieren wir es mal wie bei System.out mit der print()-Methode und schauen, was passiert.
try {
FileWriter outToFile = new FileWriter("Lorenz.txt");
// Hier kommt jetzt das Eigentliche, die Datei wird gefüllt
for ( i = 0; i < n; i++ ) {
// Berechnungen wie gehabt
outToFile.print(x);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
outToFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Hmmmmmm ....... FileWriter scheint die print()-Methode nicht zu kennen. Schauen wir mal nach, was die Enwicklungsumgebung so vorschlägt ... aha, write() könnte passen. Probieren wir es aus:
outToFile.write(x);
Diese Methode kennt FileWriter also. Lassen wir das Programm mal laufen und schauen in die Datei Lorenz.txt hinein -- hier finden wir jetzt ein paar Zeichen drin. Sehr schön, das Ganze funktioniert schon mal im Prinzip. Das Schlimmste ist geschafft.
Jetzt kümmern wir uns noch um die Formatierung. Dazu übernehmen wir den Code von oben und ersetzen "System.out" durch "outToFile" und "print" durch "write". Dabei stellen wir fest, dass writeln() nicht bekannt ist, also setzen wir den Zeilenumbruch "zu Fuß" rein:
outToFile.write(x); outToFile.write("\t");
outToFile.write(y); outToFile.write("\t");
outToFile.write(z); outToFile.write("\n");
Aber wenn wir die Datei unter Windows öffnen (mit "Notepad"), fehlen die Zeilenumbrüche. Dazu müssen wir wissen, dass ein Zeilenumbruch in Windows aus zwei Zeichen besteht: "Wagenrücklauf" ("\r") und "Zeilenvorschub" ("\n"). Probieren wir es aus:
outToFile.write(x); outToFile.write("\t");
outToFile.write(y); outToFile.write("\t");
outToFile.write(z); outToFile.write("\r\n");
Endlich. Uff, geschafft!
Dabei hatte ich mir die Mühe gemacht, das Ganze nachvollziehbar zu machen ...
Hier der Quellcode -- allerdings ohne die eigentlichen Berechnungen und was dazugehört:
import java.io.FileWriter;
import java.io.IOException;
public class gf {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// Hier kommen die Initialisierungen hin
FileWriter outToFile = null;
try {
outToFile = new FileWriter("Lorenz.txt");
for (int i=0; i<10; i++) {
// Hier kommen die ganzen Berechnungen hin
outToFile.write("Wert für x"); outToFile.write("\t");
outToFile.write("Wert für y"); outToFile.write("\t");
outToFile.write("Wert für z"); outToFile.write("\r\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
outToFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Für die Ausgabe in der Konsole würde ich dir empfehlen, mit
System.out.printf
zu arbeiten. Lies dazu hier.
Die Aufgabenstellung deines Lehrers jedoch ist eindeutig: Die Daten sollen in einer Textdatei abgespeichert werden. Eine Ausgabe auf der Konsole ist nicht gefordert.
Wie ein paar hier schon erwähnt haben kannst du natürlich das ln weglassen oder alles in eine Zeile schreiben:
System.out.println(x + " " + y + " " + z);
Dann sieht es aber meist nicht so schön aus. Versuche es so zu machen:
System.out.format("%1f%15f%15f%n", x, y, z );
Dann werden alle Zahlen schön mit einem gleichmäßigen Abstand verteilt.
Hallo nika8874,
leider vergessen viele Antworten zu beschreiben, wie man in eine Datei schreiben kann. Also, auf geht es ....
Als erstes überlege ich mir welche Ausgabe ich in eine Datei schreiben möchte und erstelle ein passendes Modell:
public class LorenzResultModel {
private double x;
private double y;
private double z;
public LorenzResultModel(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
}
Nun überlege ich mir, wie ich dieses Modell füllen könnte. Ein LorenzCalculator klingt gut, hier ist er:
import java.util.LinkedList;
import java.util.List;
public class LorenzCalculator {
private static final double T = 0.01;
private static final double START_VALUE_X = 0.1;
private static final int START_VALUE_Y = 0;
private static final int START_VALUE_Z = 0;
private static final double A = 10.0;
private static final double B = 28.0;
private static final double C = 8.0 / 3.0;
public List<LorenzResultModel> calculate(int outputCount) {
double x = START_VALUE_X;
double y = START_VALUE_Y;
double z = START_VALUE_Z;
List<LorenzResultModel> results = new LinkedList<>();
for (int i = 0; i < outputCount; i++) {
double xt = x + T * A * (y - x);
double yt = y + T * (x * (B - z) - y);
double zt = z + T * (x * y - C * z);
x = xt;
y = yt;
z = zt;
LorenzResultModel lorenzResultModel = new LorenzResultModel(x, y, z);
results.add(lorenzResultModel);
}
return results;
}
}
Für die Ausgabe in eine Datei schreibe ich mir einen LorenzModelFileWriter. Dadurch trenne ich Berechnung und Ausgabe sauber. Wenn ich möchte schreibe ich mir auch noch einen Konsolen-Writer ohne den ganzen Code anpassen zu müssen.
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import static java.lang.String.format;
public class LorenzModelFileWriter {
private final Path resultPath;
private static final String OUTPUT_PATTERN = "%1f%10f%10f%n";
public LorenzModelFileWriter(String fileName) {
resultPath = Paths.get(fileName);
}
public void write(List<LorenzResultModel> lorenzResultModels) throws IOException {
try (BufferedWriter writer = getWriter()) {
for (LorenzResultModel model : lorenzResultModels) {
String resultString = mapToString(model);
writer.write(resultString);
}
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
//You should use a Logger here
System.out.println("wrote to: " + resultPath.toAbsolutePath().toString());
}
private String mapToString(LorenzResultModel lorenzResultModel) {
//Extra mapper would be nice to use instead
return format(OUTPUT_PATTERN, lorenzResultModel.getX(), lorenzResultModel.getY(), lorenzResultModel.getZ());
}
private BufferedWriter getWriter() throws IOException {
return Files.newBufferedWriter(resultPath, Charset.forName("UTF-8"));
}
}
Damit ich auch mal eine Ausgabe erzeuge schreib ich ne kurze Main, ich verzichte auf Unit-Tests:
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception {
new Main();
}
public Main() throws Exception {
LorenzCalculator lorenzCalculator = new LorenzCalculator();
List<LorenzResultModel> lorenzResultModels = lorenzCalculator.calculate(1000);
LorenzModelFileWriter lorenzModelFileWriter = new LorenzModelFileWriter("results.txt");
lorenzModelFileWriter.write(lorenzResultModels);
}
}
Bei dem Beispiel verzichte ich bewusst auf extra Mapper für das Model, würde bei dem Beispiel nicht helfen, auch wenn es sauberer wäre. Auch verzichte ich auf Streams oder weitere Konzept, die den Code zwar sauberer machen würden, dir als Anfänger aber auch nicht helfen würden.
Gruß und viel Spaß
Könntest du mir das vielleicht alles zusammen in der reihnfolge und so schicken? Es tut mir leid du denkst dir jetzt bestimmt ich bin faul oder so aber ich habe schon die ganzen Ferien damit verbracht das hijnzubekommen. Ich habe es jetzt versucht wie du zu machen aber irgendwie funktioniert es immer noch nicht. Ich verzweifle langsam.
Hallo nika8874,
bitte? Es ist bereits in "Reihenfolge" und du musst nur den Inhalt kopieren und in die jeweilgen Dateien einfügen:
LorenzResultModel.java
LorenzCalculator.java
LorenzModelFileWriter.java
Main.java
Ich hab ja extra jede Datei gesondert geschrieben, damit Du es leicht kopieren kannst.
Gruß
Die Ausgabe in der results.txt sieht dann übrigens so aus:
0,090000 0,028000 0,000000
0,083800 0,052920 0,000025
0,080712 0,075855 0,000069
0,080226 0,097696 0,000128
0,081973 0,119182 0,000203
0,085694 0,140942 0,000295
0,091219 0,163527 0,000408
0,098450 0,187433 0,000547
...
Wie wäre es mit
System.out.print(x + " ");
System.out.print(y + " ");
System.out.print(z);
System.out.println();
oder von mir aus auch direkt so
System.out.println(x + " " + y + " " + z);
System.out.print() gibt nur das aus, was in der Klammer steht, ohne einen Zeilenumbruch zu machen. Manuellen Zeilenumbruch kannst du z.B. mit \n machen
Wäre es vielleicht möglich dass du mir das ganze zusammen schickst, also von anfang an bis zum Ende? Weil ich die reihnfolge nicht ganz verstehe und es bei mir immer noch nicht funktioniert. Es tut mir echt leid aber der Lehrer hat uns nichts gezeigt nicht einmal das mit dem try, catch finally wir müssen uns immer alles alleine beibringen und bei java tue ich mir ein bisschen schwer. Deshalb blicke ich überhaupt nicht durch. Viele werden jetzt sagen dass ich faul bin und mir alles von euch schreiben lasse, aber ich habe schon meine ganzen Ferien damit verbracht das hinzubekommen und ich bin langsam verzweifelt. Und ich möchte dir für die sehr ausführliche Antwort danken, selbst wenn ich es trotzdem nicht hinbekomme.