FileInputStream meuchelt Umlaute

Hallöle Liebste JavaFreunde,

ich habe mir ein Programm gebaut, welches in einer Textdatei schreiben und selbige auch wieder einlesen soll.
Der Quellcode von Java ist in UTF-8 gespeichert und auch die txt-Datei ist in UTF-8 gespeichert.

Das Schreiben von Umlauten in die Textdatei funktioniert ohne Probleme.
Aber wenn ich das ganze wieder einlesen möchte, kommen nur obskure Platzhalter für Sonderzeichen zustande.

Der Quellcode für beides ist folgender:


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class SpeichernGanzeDatei {
	
	public void speichern(String dateiname,String text) {
		File f = new File(dateiname);
		try {
			FileOutputStream fout = new FileOutputStream(f);
			char[] tempChar = text.toCharArray();
			byte[] source = new byte[tempChar.length];
			for(int i=0;i<tempChar.length;i++) {
				source**=(byte)tempChar**;
			}
			fout.write(source);
			fout.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public String laden(String dateiname) {
		File f = new File(dateiname);
		try {
			FileInputStream fint = new FileInputStream(f);
			byte[] temp = new byte[(int)f.length()];
			fint.read(temp);
			fint.close();
			char[] tempChar = new char[temp.length];
			String ges = "";
			for(int i=0;i<tempChar.length;i++) {
				tempChar** = (char)temp**;
				ges += tempChar**;
			}
			return ges;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static void main(String[] args) {
		SpeichernGanzeDatei sgd = new SpeichernGanzeDatei();
		String text = "äöüß";
		sgd.speichern("testdatei.txt", text);
		System.out.println(sgd.laden("testdatei.txt"));
	}

}```

Kann mir jemand sagen, wie ich den grob obskuren Fehler der Sonderzeichenliquidierung effektiv beheben kann?

Vielen Dank
Lukas

schau dir in der Schleife an, welche chars du hast, gib sie als int gecastet aus: ((int) tempChar**)
schau dir an was für bytes daraus werden,
schau dir an was für bytes eingelesen werden,
schau dir an was für chars daraus werden,
an einer Stelle ist ein Unterschied, und der ist korrigierbar


in Datei schreiben kann bei dieser Sache auch zunächst außen vor bleiben,
nur der Weg char, byte, char interessant,
kann auch alles in einer Schleife, auch mit nur einem Umlaut, drei einfachen Variablen getestet werden

aber ohne Datei weiß man natürlich nicht ob sicher, ob nicht generell nur Zeichenbrei herauskommt


beim Neuzusammenbau hast du ein char-Array als auch einen String den du Zeichen für Zeichen zusammensetzt,
wozu dann das char[], reicht doch das jeweils aktuell berechnete char hinzuzufügen?


char[] ist aber der bessere Weg, das füllen und am Ende nur 1x String daraus erstellen, String-Konstruktor

String + in einer Schleife ist eine riesige Speicher- oder eher Zeitdauerfalle,
hättest du eine Datei mit 1 MB ~ 1 Mio. Zeichen, dann würden während der Schleife 1 Mio. Strings erzeugt,
dabei erst 1 Zeichen umkopiert, dann 2, 3, 4 … 999.998, 999.999 -> Größenordnung Mio zum Quadrat = TeraByte an Daten im Speicher zu verschieben, unnötig

StringBuilder gäbe es auch noch

Hi,

du schreibst „utf-8“ aber alles was ich in deinem Code sehe ist „char** = byte**“?
Utf-8 ist eine Zeichencodierung bei der jedes Zeichen eine variabel große byte-länge besitzt. Ein Blick ins Internet hätte genügt das deutsche Umlaute aus 2 bytes bestehen.

Also jeweils 2 bytes zu einem short zusammen fassen und casten. Tip: „<<“

Würde dir aber nicht empfehlen das selber zu machen.
Nimm doch lieber die Klassen FileWriter und FileReader bevor du dir die Arbeit machst einen Utf-8 Decodierer per Hand zu schreiben.
Falls du letzteres doch vor hast würde ich dir aber vorher Wikipedia nahelegen, nettes kleines Lexikon, da kann man bestimmt auch utf-8 nachlesen :stuck_out_tongue:
Kleiner Scherz am Rande, aber trotzdem am besten mal utf-8 besser studieren wenn du damit auf low-level arbeiten möchtest.

Beste Grüße
TMII

In- und OutputStream sind ziemlich low-level.

Für Text-Dateien arbeitet man besser mit Writer/Reader.



BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inFile), Charset.forName("UTF-8")));```


bye
TT

Hallöle,

ich danke euch vielmals für eure Antworten. Ich bin immer wieder begeistert über die Hilfsbereitschaft in diesem Forum, auch bei teilweise sehr amateurhaften Fragen wie den meinen. Dankeschön! :slight_smile:

Ich habe versucht all eure Antworten zu konglomerieren und auf alle guten Tipps zu achten und bin auf einen sehr übersichtlichen Quellcode gekommen, der auch mit guter Laufzeit genau das, was er macht.

Bei etwaigen Fehlern oder weiteren Verbesserungen, wäre es schön, wenn das jemand sagen könnte. :slight_smile:
@Timothy_Truckle
Vielen Dank für den Tipp mit den BufferedWritern/Readern. Ich habe es in meinen Quellcode einsetzen können und stelle fest, es läuft gefühlt um einiges besser. Auch kannte ich das mit dem Charset noch nicht, das ist eine sehr nette Sache, die Dir noch viele meiner Projekte danken werden. :slight_smile:
@TMII
Diese ganze Codierungssache wird mich noch ins Grab bringen. Ich hatte bis dato immer riesige Probleme mit Sonderzeichenumcodierung zwischen Linux/Mac und Windows. eine von Dir erzwungene Recherche meinerseits und Deine Erklärung dazu ließen das viel klarer werden.
@SlaterB
In der Tat, Du hast absolut recht. Insbesondere die Einlesemethode fand ich partiell obskur, weil sich das alles wirklich etwas überlagert und wiederholt hat. Auch stellte ich fest, dass die Sache mit dem Einzelnen String hinzufügen eine halbe Ewigkeit dauert. TeraByteWeise war das jetzt nicht, aber bei ein paar HundertTausend Zeichen hab ich schon ne halbe Minute benötigt.

Der Gesamtquelltext sieht nun so aus:


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;

public class SpeichernGanzeDatei {
	
	public void speichern(String dateiname,String text) {
		try {
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dateiname), Charset.forName("UTF-8")));
			char[] tempChar = text.toCharArray();
			bw.write(tempChar);
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public String laden(String dateiname) {
		File f = new File(dateiname);
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(dateiname), Charset.forName("UTF-8")));
			char[] tempChar = new char[(int)f.length()];
			br.read(tempChar);
			br.close();
			
			String ges = new String(tempChar);
			return ges;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static void main(String[] args) {
		SpeichernGanzeDatei sgd = new SpeichernGanzeDatei();
		String text = "Weit hinten, hinter den Wortbergen, fern der Länder Vokalien und Konsonantien leben die Blindtexte.Abgeschieden wohnen Sie in Buchstabhausen an der Küste des Semantik, eines großen Sprachozeans. Ein kleines Bächlein namens Duden fließt durch ihren Ort und versorgt sie mit den nötigen Regelialien. Es ist ein paradiesmatisches Land, in dem einem gebratene Satzteile in den Mund fliegen. Nicht einmal von der allmächtigen Interpunktion werden die Blindtexte beherrscht – ein geradezu unorthographisches Leben. Eines Tages aber beschloß eine kleine Zeile Blindtext, ihr Name war Lorem Ipsum, hinaus zu gehen in die weite Grammatik. Der große Oxmox riet ihr davon ab, da es dort wimmele von bösen Kommata, wilden Fragezeichen und hinterhältigen Semikoli, doch das Blindtextchen ließ sich nicht beirren. Es packte seine sieben Versalien, schob sich sein Initial in den Gürtel und machte sich auf den Weg. Als es die ersten Hügel des Kursivgebirges erklommen hatte, warf es einen letzten Blick zurück auf die Skyline seiner Heimatstadt Buchstabhausen, die Headline von Alphabetdorf und die Subline seiner eigenen Straße, der Zeilengasse. Wehmütig lief ihm eine rethorische Frage über die Wange, dann setzte es seinen Weg fort. Unterwegs traf es eine Copy. Die Copy warnte das Blindtextchen, da, wo sie herkäme wäre sie zigmal umgeschrieben worden und alles, was von ihrem Ursprung noch übrig wäre, sei das Wort “und” und das Blindtextchen solle umkehren und wieder in sein eigenes, sicheres Land zurückkehren. Doch alles Gutzureden konnte es nicht überzeugen und so dauerte es nicht lange, bis ihm ein paar heimtückische Werbetexter auflauerten, es mit Longe und Parole betrunken machten und es dann in ihre Agentur schleppten, wo sie es für ihre Projekte wieder und wieder mißbrauchten. Und wenn es nicht umgeschrieben wurde, dann benutzen Sie es immernoch.";
		sgd.speichern("testdatei.txt", text);
		System.out.println(sgd.laden("testdatei.txt"));
	}

}```

Wie in der Main-Methode zu sehen, speichere ich in die Textdatei zuerst einen Text ein und lese denselben dann sofort wieder ein.
Ergo muss also
a) in der Textdatei dann der Text drin sein
b) die Konsole den Text selbst wieder ausgeben

Hat beides geklappt, inklusive Umlaute.

Der Vollständigkeit halber nenne ich noch die Quelle für den Text: [Beispieltext – deutsch | Oh nein!](http://fluegge.net/ohnein/beispieltext-deutsch/)
Ist einfaches eines der ersten Google-Suchergebnisse für Beispieltexte auf Deutsch.

Viele Grüße
Lukas

InputStreamReader ist zwar korrekt, im Sinne der Aufgabe aber Cheaten :wink:

die Umlaute waren (UTF8-gesehen) hohe chars a la 246, ergo -10 für byte-Bereich -128 bis +127,
eingelesen wieder als -10, auf char gecastet 65526 (Maximum -10),
wenn man da für Negative schlicht x + 256 gerechnet hätte, dann für diesen Bereich auch schon wieder ok