1. Eine Datei vollständig lesen
Alle Bytes lesen
Manchmal muss man den gesamten Inhalt einer Datei auf einmal herausziehen – so wie er ist, ohne Interpretation, sei es ein Bild, ein Archiv oder irgendein Binärformat. Dafür gibt es in Java die Methode Files.readAllBytes(path). Sie liefert ein Byte-Array (byte[]), also die rohen Dateidaten, die Sie anschließend nach Belieben verwenden können.
import java.nio.file.*;
public class ReadBytesExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get("example.txt");
byte[] allBytes = Files.readAllBytes(path);
System.out.println("Dateilänge in Bytes: " + allBytes.length);
}
}
Hinweis: Wenn die Datei groß ist (Gigabytes), kann dieser Ansatz zu Speicherproblemen führen – denn der gesamte Inhalt wird sofort in den Arbeitsspeicher geladen.
Alle Zeilen lesen
Für Textdateien gibt es eine angenehmere Variante: Files.readAllLines(path). Sie liefert eine Liste von Zeilen (List<String>), wobei jedes Element genau einer Zeile der Datei entspricht (Zeilentrenner werden automatisch berücksichtigt).
import java.nio.file.*;
import java.util.List;
public class ReadLinesExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get("example.txt");
List<String> lines = Files.readAllLines(path);
for (String line : lines) {
System.out.println(line);
}
}
}
Wichtig: Standardmäßig wird die Systemzeichencodierung verwendet. Wenn Sie die Codierung explizit angeben möchten (z. B. UTF-8), verwenden Sie die überladene Methodenversion:
List<String> lines = Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);
Beispiel: Datei lesen und auf dem Bildschirm ausgeben
Fügen wir das in unsere Mini‑App ein (zum Beispiel „Notizblock“ oder „To‑do‑Liste“):
import java.nio.file.*;
import java.util.List;
public class TodoReader {
public static void main(String[] args) throws Exception {
Path todoPath = Paths.get("todo.txt");
if (Files.exists(todoPath)) {
List<String> tasks = Files.readAllLines(todoPath);
System.out.println("Ihre Aufgaben für heute:");
for (String task : tasks) {
System.out.println("- " + task);
}
} else {
System.out.println("Die Datei todo.txt wurde nicht gefunden. Erstellen Sie eine Aufgabenliste!");
}
}
}
2. In eine Datei schreiben
Ein Byte-Array schreiben
Wenn Sie ein Byte-Array haben (z. B. das Ergebnis einer Serialisierung, ein Bild, Audio), verwenden Sie Files.write(path, bytes). Diese Methode erstellt die Datei, falls sie nicht existiert, oder überschreibt eine vorhandene.
import java.nio.file.*;
public class WriteBytesExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get("output.bin");
byte[] data = {1, 2, 3, 4, 5};
Files.write(path, data);
System.out.println("Bytes wurden in die Datei output.bin geschrieben");
}
}
Eine Liste von Zeilen schreiben
Für Textdateien ist es bequemer, eine Liste von Zeilen zu verwenden – jede Zeile wird separat mit einem Zeilenumbruch geschrieben.
import java.nio.file.*;
import java.util.Arrays;
import java.util.List;
public class WriteLinesExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get("todo.txt");
List<String> tasks = Arrays.asList(
"Milch kaufen",
"Oma anrufen",
"Java-Hausaufgaben machen"
);
Files.write(path, tasks);
System.out.println("Die Aufgabenliste wurde in todo.txt geschrieben");
}
}
Achtung: Standardmäßig wird die Datei überschrieben! Wenn sie bereits existierte, sind die alten Aufgaben weg. (Wie man Altes nicht verliert – dazu gleich mehr.)
Eine Zeichenkette in eine Datei schreiben
Wenn Sie nur eine einzige Zeile schreiben möchten, erstellen Sie einfach eine Liste mit einer Zeile oder verwenden Sie Files.write(path, string.getBytes()):
import java.nio.file.*;
public class WriteStringExample {
public static void main(String[] args) throws Exception {
Path path = Paths.get("hello.txt");
String message = "Hallo, Java!";
Files.write(path, message.getBytes());
System.out.println("Die Zeile wurde in hello.txt geschrieben");
}
}
Zeichencodierung explizit angeben
Um „Zeichensalat“ bei der Arbeit mit russischem (und anderem) Text zu vermeiden, geben Sie die Codierung stets explizit an:
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;
public class WriteLinesUtf8Example {
public static void main(String[] args) throws Exception {
Path path = Paths.get("hello.txt");
List<String> lines = List.of("Hallo, Welt!", "Das ist Java.");
Files.write(path, lines, StandardCharsets.UTF_8);
}
}
3. Fehlerbehandlung
Bei der Arbeit mit Dateien kann Java die Ausnahme IOException auslösen. Das ist ein allgemeines Signal dafür, dass „irgendetwas“ auf der Ein-/Ausgabeebene schiefgelaufen ist. Gründe gibt es viele: Die Datei existiert nicht, es fehlen Zugriffsrechte, das Laufwerk ist voll oder belegt, oder jemand hat sogar den USB-Stick im unpassendsten Moment herausgezogen.
Deshalb verlangen Methoden zum Lesen und Schreiben von Dateien von uns, auf solche Situationen vorbereitet zu sein. Das geschieht mit try-catch:
import java.nio.file.*;
import java.util.List;
import java.io.IOException;
public class SafeReadExample {
public static void main(String[] args) {
Path path = Paths.get("todo.txt");
try {
List<String> lines = Files.readAllLines(path);
System.out.println("Dateiinhalt:");
for (String line : lines) {
System.out.println(line);
}
} catch (IOException ex) {
System.out.println("Fehler beim Lesen der Datei: " + ex.getMessage());
}
}
}
Wozu das Ganze?
try-catch verwandelt einen potenziellen Absturz des Programms in eine kontrollierte Situation. Gibt es die Datei nicht – informieren wir den Nutzer ruhig. Verweigert das System den Zugriff – weisen wir auf das Problem hin. Und wenn das Laufwerk mitten in der Operation verschwindet, stürzt das Programm nicht mit einem hässlichen Stacktrace ab, sondern warnt zumindest mit einer verständlichen Meldung. Anders gesagt: IOException ist kein Feind, sondern lediglich die Art und Weise, wie Java uns mitteilt: „Hey, draußen ist etwas schiefgelaufen – überleg dir, wie es weitergehen soll.“
4. Praxisbeispiele
Datei lesen und Inhalt ausgeben
import java.nio.file.*;
import java.util.List;
import java.io.IOException;
public class PrintFileExample {
public static void main(String[] args) {
Path path = Paths.get("notes.txt");
try {
if (!Files.exists(path)) {
System.out.println("Die Datei notes.txt wurde nicht gefunden.");
return;
}
List<String> lines = Files.readAllLines(path, java.nio.charset.StandardCharsets.UTF_8);
System.out.println("Inhalt der Datei notes.txt:");
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Fehler beim Lesen der Datei: " + e.getMessage());
}
}
}
Eine Zeile in eine neue Datei schreiben
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
public class WriteFileExample {
public static void main(String[] args) {
Path path = Paths.get("greeting.txt");
String content = "Willkommen in der Welt von Java IO!";
try {
Files.write(path, content.getBytes(StandardCharsets.UTF_8));
System.out.println("Die Zeile wurde in die Datei greeting.txt geschrieben");
} catch (IOException e) {
System.out.println("Fehler beim Schreiben der Datei: " + e.getMessage());
}
}
}
Eine Liste von Zeilen in eine Datei schreiben
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.io.IOException;
public class WriteListExample {
public static void main(String[] args) {
Path path = Paths.get("shopping.txt");
List<String> items = List.of("Brot", "Milch", "Käse");
try {
Files.write(path, items, StandardCharsets.UTF_8);
System.out.println("Die Einkaufsliste wurde in shopping.txt geschrieben");
} catch (IOException e) {
System.out.println("Fehler beim Schreiben der Datei: " + e.getMessage());
}
}
}
5. Kurz zu Streams
Die Methoden Files.readAllBytes, Files.readAllLines, Files.write sind „alles auf einmal“: entweder die gesamte Datei in den Speicher oder der gesamte Inhalt sofort auf die Platte. Für kleine Dateien ist das bequem, für große – nicht so sehr (es kann zu OutOfMemoryError kommen oder das Lesen gigabytegroßer Logs kann einfach „hängen bleiben“).
Für die Arbeit mit großen Dateien oder für zeilenweises Lesen verwendet man Streams:
- Für Text: BufferedReader, BufferedWriter
- Für Bytes: InputStream, OutputStream
Über Streams sprechen wir ausführlicher in den nächsten Vorlesungen, hier ein kleiner Teaser:
import java.nio.file.*;
import java.io.*;
public class BufferedReaderExample {
public static void main(String[] args) {
Path path = Paths.get("bigfile.txt");
try (BufferedReader reader = Files.newBufferedReader(path)) {
String line;
while ((line = reader.readLine()) != null) {
// Zeile verarbeiten
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Fehler beim Lesen der Datei: " + e.getMessage());
}
}
}
6. Nützliche Details
- Überschreiben der Datei: Alle Methoden Files.write überschreiben die Datei standardmäßig. Wenn Sie ans Ende anhängen möchten, verwenden Sie zusätzliche Optionen (mehr dazu in der nächsten Vorlesung).
- Zeichencodierung: Geben Sie die Codierung immer explizit an, wenn Sie mit nicht-ASCII-Text arbeiten. Das erspart „Zeichensalat“ im Ergebnis. Eine gute Wahl ist StandardCharsets.UTF_8.
- Pfade: Verwenden Sie Paths.get(...) für Plattformunabhängigkeit. Hardcoden Sie Schrägstriche niemals manuell (/ oder \).
- Dateinamen: Verwenden Sie in Dateinamen keine verbotenen Zeichen (?, *, :, <, >, | usw.), besonders wenn Ihr Code unter Windows laufen soll.
7. Typische Fehler beim Lesen und Schreiben von Dateien
Fehler Nr. 1: IOException wird nicht behandelt. Anfänger schreiben sehr oft Files.readAllLines(path) ohne try-catch, und beim ersten Problem (Datei nicht gefunden, fehlende Rechte, defektes Laufwerk) stürzt das Programm ab. Behandeln Sie Ausnahmen immer!
Fehler Nr. 2: Große Dateien mit readAllBytes/readAllLines verarbeiten. Wenn eine Datei hunderte Megabytes oder mehrere Gigabytes groß ist, kann der Versuch, sie vollständig zu laden, Ihr Programm „umbringen“. In solchen Fällen verwenden Sie Streams (BufferedReader).
Fehler Nr. 3: Keine Zeichencodierung beim Schreiben/Lesen von Text angegeben. Ohne Angabe der Codierung kann das Ergebnis auf verschiedenen Rechnern und Betriebssystemen variieren. Besonders häufig zeigt sich das Problem bei kyrillischer Schrift. Verwenden Sie StandardCharsets.UTF_8 oder geben Sie die benötigte Codierung explizit an.
Fehler Nr. 4: Annehmen, dass File/Path die Datei selbst ist. Die Klassen File bzw. Path sind nur ein „Verweis“ auf eine Datei, nicht die Datei selbst. Durch das Erzeugen eines Objekts entsteht noch keine Datei auf dem Datenträger. Um eine Datei zu erstellen – verwenden Sie Methoden wie Files.createFile, Files.write und so weiter.
Fehler Nr. 5: Stream wird nicht geschlossen (wenn Sie Streams verwenden). Wenn Sie Streams manuell verwenden (z. B. BufferedReader), schließen Sie sie unbedingt (am besten via try-with-resources). Andernfalls kann die Datei „gelockt“ bleiben und für andere Programme nicht verfügbar sein.
GO TO FULL VERSION