EMZETT.
Login

I/O Streams

Kurz: Ein Datenstrom, über den ein Programm sequenziell Daten liest (Input) oder schreibt (Output) — die gemeinsame Abstraktion hinter Datei-, Netzwerk- und Konsolen-Ein-/Ausgabe.

Genauer: Streams verarbeiten Daten üblicherweise Stück für Stück statt alles auf einmal, was auch sehr große Datenmengen handhabbar macht, ohne sie komplett im Speicher zu halten. Man unterscheidet Byte-Streams (rohe Bytes, z. B. FileInputStream) und Zeichen-Streams (Text mit Zeichenkodierung), sowie ungepufferte und gepufferte Varianten.

Im Detail

Der zentrale Vorteil eines Streams gegenüber “alles auf einmal einlesen” zeigt sich bei großen Dateien: Eine 10-GB-Logdatei komplett in den Speicher zu laden, bevor man sie verarbeitet, würde in den meisten Systemen den verfügbaren Arbeitsspeicher sprengen — ein Stream liest stattdessen z. B. immer nur die aktuelle Zeile oder einen festen Byte-Block, verarbeitet ihn, und verwirft ihn danach wieder.

stream = oeffne_datei("riesige_logdatei.txt")
solange stream.hat_naechste_zeile():
    zeile = stream.lies_naechste_zeile()
    verarbeite(zeile)
stream.schliessen()

Streams lassen sich grob nach zwei Achsen unterscheiden:

  • Richtung: Input-Stream (Lesen) vs. Output-Stream (Schreiben) — für Ein- und Ausgabe braucht man meist getrennte Stream-Objekte, auch wenn sie dieselbe Quelle/Ziel ansprechen.
  • Pufferung: Ein ungepufferter Stream fragt bei jedem einzelnen Lese-/Schreibvorgang direkt beim Betriebssystem/der Festplatte an, was bei vielen kleinen Operationen langsam ist. Ein gepufferter Stream sammelt intern erst einen größeren Block im Speicher (Puffer) und reicht Daten daraus weiter — deutlich schneller bei vielen kleinen Lese-/Schreib-Aufrufen, kostet aber etwas zusätzlichen Speicher.

Ein wichtiger, häufig vergessener Punkt: Ein offener Stream belegt eine Betriebssystem-Ressource (einen Dateideskriptor/Handle) — wird der Stream nicht explizit geschlossen (z. B. per close() oder mit einem Sprachkonstrukt wie Javas try-with-resources, das das automatisch übernimmt), bleibt diese Ressource belegt, selbst wenn das Programm mit der Datei fertig ist. Bei vielen offenen, nie geschlossenen Streams kann ein langlaufendes Programm irgendwann keine neuen Dateien mehr öffnen (“zu viele offene Dateien”).

Siehe auch: FileInputStream, BufferedReader, Files