Java Daten nicht untereinander sondern nebeneinander ausgeben?

7 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

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!

Woher ich das weiß:Berufserfahrung – Software-Entwickler

nika8874 
Fragesteller
 30.05.2018, 13:06

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.

0
PWolff  30.05.2018, 14:24
@nika8874

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();
            }    
        }
        
    }

}


1
PWolff  30.05.2018, 14:41
@PWolff

Ach ja, statt "Wert für x" etc. muss natürlich nur x etc. dahin.

1

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.

Zum Schreiben von Dateien lies hier oder hier.

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.

http://tpcg.io/WSyAPU

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ß


AldoradoXYZ  29.05.2018, 13:42

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
...

0
nika8874 
Fragesteller
 30.05.2018, 13:19

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.

0
AldoradoXYZ  30.05.2018, 13:21
@nika8874

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ß

0

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

Woher ich das weiß:Berufserfahrung – Freiberuflicher Java Entwickler mit 10 Jahren Erfahrung