Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Diese Lerneinheit wurde für typische Bachelor-Klausuren konzipiert. So prüfen wir · Fehler entdeckt? Melde ihn uns oder markiere die fragliche Stelle direkt im Text oben.
Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Sobald dein Programm mit der Außenwelt redet, eine Datei liest, eine schreibt, übers Netzwerk kommuniziert, läuft das über Streams: einen Fluss von Daten, der Stück für Stück gelesen oder geschrieben wird. Java trennt dabei sauber zwischen Byte-Strömen (für Binärdaten) und Zeichen-Strömen (für Text). Wer das verwechselt, bekommt kaputte Umlaute oder unnötig komplizierten Code.
Was du können musst:
InputStream/OutputStream) von Char-Streams (Reader/Writer) unterscheidenread() liefert -1, readLine() liefert null)BufferedReader schneller ist)Abgrenzung: hier die Grundlagen der Datei-I/O. Tiefes NIO (Channels, Buffers, Memory-Mapped Files, asynchrones I/O) ist Vertiefung.
Klausur-Tipp: Zwei Fragen kommen fast immer: (1) "Wie erkennt die Schleife das Dateiende?" Antwort: read() → -1, readLine() → null. (2) "Warum BufferedReader?" Antwort: weniger Festplatten-Zugriffe (Buffer statt byteweise). Und: nenne try-with-resources fürs sichere Schließen.
Anmelden, um den Fortschritt zu speichern.
Nächster Schritt
Aktives Abrufen festigt Wissen schneller als nochmal lesen.
Sobald dein Programm mit der Außenwelt redet, eine Datei liest, eine schreibt, übers Netzwerk kommuniziert, läuft das über Streams: einen Fluss von Daten, der Stück für Stück gelesen oder geschrieben wird. Java trennt dabei sauber zwischen Byte-Strömen (für Binärdaten) und Zeichen-Strömen (für Text). Wer das verwechselt, bekommt kaputte Umlaute oder unnötig komplizierten Code.
Was du können musst:
InputStream/OutputStream) von Char-Streams (Reader/Writer) unterscheidenread() liefert -1, readLine() liefert null)BufferedReader schneller ist)Abgrenzung: hier die Grundlagen der Datei-I/O. Tiefes NIO (Channels, Buffers, Memory-Mapped Files, asynchrones I/O) ist Vertiefung.
Ein Stream ist ein Datenfluss:
InputStream/Readerliest Daten herein,OutputStream/Writerschreibt hinaus, Stück für Stück, bis das Ende (EOF) erreicht ist.
| Byte-Streams | Char-Streams | |
|---|---|---|
| Basisklassen | InputStream, OutputStream | Reader, Writer |
| Einheit | Byte (0-255) | Zeichen (mit Encoding) |
| Wofür | Binärdaten: Bilder, Audio, serialisierte Objekte | Text: .txt, .csv, .json |
| EOF-Signal | read() liefert -1 | readLine() liefert null |
Faustregel: Text → Char-Stream (Reader/Writer), alles andere → Byte-Stream. Ein Char-Stream wandelt Bytes über ein Encoding (Charset, meist UTF-8) in Zeichen um; ein Byte-Stream tut das nicht.
// Byte-Stream: Datei roh als Bytes lesen
try (InputStream in = new FileInputStream("bild.png")) {
int b;
while ((b = in.read()) != -1) { /* b ist ein Byte 0-255 */ }
}
// Char-Stream: Textdatei zeilenweise lesen (mit Encoding)
try (BufferedReader br = Files.newBufferedReader(Path.of("text.txt"))) {
String zeile;
while ((zeile = br.readLine()) != null) { System.out.println(zeile); }
}
Das häufigste Klausur-Detail: woran erkennt die Schleife das Dateiende? Bei einem Byte-Stream liefert read() einen int zurück, das gelesene Byte (0 bis 255) oder -1, wenn nichts mehr kommt. -1, nicht 0, denn 0 ist ein gültiges Byte. Verfolge den Lese-Loop:
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Jeder ungepufferte read() löst potenziell einen Festplatten-Zugriff (System-Call) aus, byteweise ist das extrem langsam. Ein Buffer liest einen großen Block auf einmal in den Speicher; die folgenden read()-Aufrufe werden dann aus dem RAM bedient.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Für die meisten Fälle reicht heute die knappe NIO-API aus java.nio.file:
// ganze Datei als String (kleine Dateien)
String inhalt = Files.readString(Path.of("text.txt")); // UTF-8
// alle Zeilen als Liste
List<String> zeilen = Files.readAllLines(Path.of("text.txt"));
// schreiben
Files.writeString(Path.of("out.txt"), "Hallo");
// gepufferter Reader (grosse Dateien, zeilenweise)
try (BufferedReader br = Files.newBufferedReader(Path.of("gross.txt"))) { ... }
Files.readString/readAllLinesladen die ganze Datei in den Speicher, ideal für kleine Dateien. Für große Dateien zeilenweise mitBufferedReaderstreamen.
1. Text → Char-Stream, Binär → Byte-Stream. Reader/Writer für .txt/.csv/.json, InputStream/OutputStream für Bilder, Audio, serialisierte Objekte.
2. EOF-Signale auseinanderhalten. Byte-read() liefert -1 am Ende, readLine() liefert null. Beides ist nicht 0 und nicht "" (leerer String).
3. Immer puffern. BufferedReader/BufferedInputStream macht aus vielen kleinen Festplatten-Zugriffen wenige große, oft drastisch schneller.
4. Encoding explizit setzen. Char-Streams wandeln Bytes über ein Charset (UTF-8). Ohne Angabe greift der Plattform-Default, das ist nicht portabel und zerschießt Umlaute.
5. Ressourcen mit try-with-resources schließen. Datei/Stream schließen, auch im Fehlerfall, sonst Resource-Leak.
6. NIO (Files/Path) für knappe Standard-Fälle. Files.readString, Files.readAllLines, Files.writeString ersetzen viel altes Boilerplate.
1. EOF-Bedingung falsch. while (in.read() != 0) statt != -1 läuft ewig oder bricht beim ersten Null-Byte ab. Bei readLine() ist die Bedingung != null, sonst NullPointerException.
2. Byte-Stream für Text. Direkt Bytes lesen und in chars casten ignoriert das Encoding, Mehrbyte-Zeichen (ä, ö, ü, Emojis) zerbrechen. Für Text immer Reader/Writer.
3. Nicht puffern. Byteweise von der Platte lesen ohne Buffer ist um Größenordnungen langsamer. Im Zweifel BufferedReader drumherum.
4. Datei nicht geschlossen. Ohne close() (oder try-with-resources) bleibt der File-Handle offen, Resource-Leak, bei vielen offenen Dateien "too many open files".
5. Encoding nicht angegeben. new FileReader(...) nutzt den Plattform-Default. Besser Files.newBufferedReader(path) (UTF-8) oder das Charset explizit angeben.
6. read() liefert int, nicht byte. Wer den Rückgabewert vorschnell in byte castet, kann -1 (EOF) nicht mehr von 255 unterscheiden. Erst auf -1 prüfen, dann casten.
Der Standard-Weg, eine Textdatei zu verarbeiten: gepufferter Reader, Zeile für Zeile, bis readLine() null liefert, und automatisch geschlossen per try-with-resources. Achte im Stepper auf das null-Signal (das Char-Pendant zum -1 der Byte-Streams).
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Zwei Fragen kommen fast immer: (1) "Wie erkennt die Schleife das Dateiende?" Antwort: read() → -1, readLine() → null. (2) "Warum BufferedReader?" Antwort: weniger Festplatten-Zugriffe (Buffer statt byteweise). Und: nenne try-with-resources fürs sichere Schließen.
Klausurfragen mit Lösungen (6)
Antwort: Reader / BufferedReader (Char-Stream)
Erklärung: Fuer Text nutzt man Char-Streams (Reader/BufferedReader): sie wandeln Bytes ueber ein Encoding (UTF-8) in Zeichen. Byte-Streams (InputStream) sind fuer Binaerdaten und kennen kein Encoding, Umlaute wuerden zerbrechen.
Antwort: -1
Erklärung: read() liefert das naechste Byte (0-255) oder -1 bei EOF. NICHT 0 (das ist ein gueltiges Byte) und nicht null (read gibt einen int zurueck). Das Char-Pendant readLine() liefert dagegen null bei EOF.
Antwort: Wahr
Erklärung: Richtig. Statt pro Byte/Zeichen einen Festplatten-Zugriff (Syscall) zu machen, liest der Puffer einen grossen Block auf einmal und bedient die folgenden read()-Aufrufe aus dem Speicher. Oft Faktor 10-100 schneller.
Typ: Wahr/Falsch
Antwort: Die Datei wird automatisch geschlossen, auch wenn eine Exception fliegt
Erklärung: try-with-resources ruft close() automatisch auf, am Ende des Blocks und auch im Fehlerfall. Das verhindert Resource-Leaks (offene File-Handles). Mit Performance, Encoding oder Buffering hat es nichts zu tun.
Zuordnungen:
Erklärung: InputStream/OutputStream = Bytes (binär), Reader/Writer = Zeichen (Text). BufferedReader puffert und bietet readLine().
Typ: Zuordnung
byte b;
while ((b = (byte) in.read()) != -1) { ... }Antwort: Ein Byte 255 wird als (byte) zu -1, dann bricht die Schleife fälschlich beim Wert 255 ab
Erklärung: read() gibt absichtlich einen int (0-255 oder -1) zurueck, damit EOF (-1) von jedem gueltigen Byte unterscheidbar ist. Castet man zu byte, wird 255 zu -1 (byte ist signed, -128..127), und die Schleife bricht beim Datenbyte 255 faelschlich ab. Erst auf -1 pruefen, dann casten.
Klausurfragen mit Lösungen (6)
Antwort: null
Erklärung: readLine() liefert die naechste Zeile als String oder null bei EOF. Ein leerer String ("") ist eine gueltige Leerzeile, NICHT das Ende. Byte-read() nutzt dagegen -1.
Antwort: Files.readString(path)
Erklärung: Files.readString(path) liest die komplette Datei als String (UTF-8), ideal fuer kleine Dateien. Fuer grosse Dateien besser zeilenweise mit BufferedReader streamen, statt alles in den Speicher zu laden.
Antwort: Falsch
Erklärung: Falsch. Ein Byte-Stream kennt kein Encoding. Mehrbyte-Zeichen wie ä/ö/ü (in UTF-8 mehrere Bytes) zerbrechen, wenn man sie byteweise als Zeichen interpretiert. Fuer Text nimmt man Char-Streams (Reader), die ueber ein Charset dekodieren.
Typ: Wahr/Falsch
Lösungen pro Lücke:
Erklärung: Byte-Streams (binär) vs. Char-Streams (Text). EOF: read() liefert -1, readLine() liefert null. Standard-Klausurwissen der Datei-I/O.
Typ: Lückentext
Antwort: Sonst wird der Plattform-Default benutzt, was nicht portabel ist und Umlaute zerstören kann
Erklärung: Ohne explizites Charset nimmt Java den Plattform-Default (z.B. Windows-1252 vs. UTF-8). Dieselbe Datei wird dann auf verschiedenen Systemen unterschiedlich dekodiert, Umlaute und Sonderzeichen zerbrechen. Files.newBufferedReader nutzt standardmaessig UTF-8.
FileReader fr = new FileReader("daten.txt");
int c;
while ((c = fr.read()) != 0) {
System.out.print((char) c);
}Antwort: Die Bedingung != 0 ist falsch: EOF ist -1, nicht 0; ausserdem wird die Datei nie geschlossen
Erklärung: Zwei Fehler: (1) Das EOF-Signal von read() ist -1, nicht 0, die Bedingung muss != -1 lauten (mit != 0 laeuft die Schleife ueber das Dateiende hinaus weiter). (2) fr wird nie geschlossen, Resource-Leak. Besser: try-with-resources + != -1.