Kurz: Das Paket java.nio.file (NIO.2) ist der moderne Weg, mit Dateien zu arbeiten: Path beschreibt einen Pfad, Files erledigt die Arbeit.
Teil des Kurses Java
Das Paket java.nio.file (NIO.2) ist der moderne Weg, mit Dateien zu arbeiten: Path beschreibt einen Pfad, Files erledigt die Arbeit.
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
public class Dateien {
public static void main(String[] args) throws IOException {
Path ordner = Files.createTempDirectory("kurs");
Path datei = ordner.resolve("notiz.txt"); // Pfad zusammensetzen
Files.writeString(datei, "Zeile 1\nZeile 2\n");
Files.writeString(datei, "Zeile 3\n", StandardOpenOption.APPEND);
String inhalt = Files.readString(datei);
List<String> zeilen = Files.readAllLines(datei);
System.out.println(zeilen + " " + inhalt.length());
System.out.println(Files.exists(datei) + " " + Files.size(datei) + " " + datei.getFileName());
Path kopie = ordner.resolve("kopie.txt");
Files.copy(datei, kopie);
try (var strom = Files.list(ordner)) {
strom.map(p -> p.getFileName().toString()).sorted().forEach(System.out::println);
}
Files.delete(kopie);
Files.delete(datei);
Files.delete(ordner);
System.out.println(Files.exists(ordner));
}
}Ausgabe:
[Zeile 1, Zeile 2, Zeile 3] 24
true 24 notiz.txt
kopie.txt
notiz.txt
falseAlle Methoden können eine IOException werfen. Schreibe throws IOException oder fange sie.
Zeilenweise lesen
Große Dateien liest man nicht komplett, sondern Zeile für Zeile:
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
public class Zeilen {
public static void main(String[] args) throws IOException {
Path p = Files.createTempFile("daten", ".txt");
Files.write(p, java.util.List.of("Mia;17", "Tom;19", "Zoe;21"), StandardCharsets.UTF_8);
try (BufferedReader r = Files.newBufferedReader(p)) {
String zeile;
int summe = 0;
while ((zeile = r.readLine()) != null) {
String[] teile = zeile.split(";");
summe += Integer.parseInt(teile[1]);
}
System.out.println("Summe der Alter: " + summe);
}
try (var stream = Files.lines(p)) { // als Stream
System.out.println(stream.filter(z -> z.contains("o")).count());
}
try (BufferedWriter w = Files.newBufferedWriter(p)) {
w.write("neu");
w.newLine();
}
System.out.println(Files.readString(p).trim());
Files.delete(p);
}
}Ausgabe:
Summe der Alter: 57
2
neuGib den Zeichensatz an (StandardCharsets.UTF_8), wenn Umlaute vorkommen.
Pfade
import java.nio.file.*;
public class Pfade {
public static void main(String[] args) {
Path p = Path.of("ordner", "unter", "bild.png");
System.out.println(p + " " + p.getFileName() + " " + p.getParent() + " " + p.getNameCount());
System.out.println(Path.of("/a/b/../c/./d").normalize());
System.out.println(Path.of("/a/b").relativize(Path.of("/a/b/c/d")));
System.out.println(p.toString().endsWith(".png") + " " + p.isAbsolute());
}
}Ausgabe:
ordner/unter/bild.png bild.png ordner/unter 3
/a/c/d
c/d
true falseOrdner durchlaufen
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.*;
public class Baum {
public static void main(String[] args) throws IOException {
Path wurzel = Files.createTempDirectory("baum");
Files.createDirectories(wurzel.resolve("a/b"));
Files.writeString(wurzel.resolve("a/eins.txt"), "1");
Files.writeString(wurzel.resolve("a/b/zwei.txt"), "22");
try (Stream<Path> s = Files.walk(wurzel)) {
s.filter(Files::isRegularFile)
.map(p -> wurzel.relativize(p).toString())
.sorted()
.forEach(System.out::println);
}
try (Stream<Path> s = Files.walk(wurzel)) { // aufräumen: tiefste zuerst
s.sorted(java.util.Comparator.reverseOrder()).forEach(p -> p.toFile().delete());
}
System.out.println(Files.exists(wurzel));
}
}Ausgabe:
a/b/zwei.txt
a/eins.txt
falseEingabe von der Tastatur
Mit Scanner liest du Eingaben. Er funktioniert auch mit Texten statt Tastatur:
import java.util.Scanner;
public class Eingabe {
public static void main(String[] args) {
Scanner sc = new Scanner("Mia 17\n3.5\nein ganzer Satz\n"); // statt System.in
String name = sc.next();
int alter = sc.nextInt();
double zahl = sc.nextDouble();
sc.nextLine(); // Rest der Zeile verwerfen
String satz = sc.nextLine();
System.out.println(name + " " + alter + " " + zahl + " | " + satz);
System.out.println(sc.hasNextLine());
}
}Ausgabe:
Mia 17 3.5 | ein ganzer Satz
falseIm echten Programm: new Scanner(System.in). Nach nextInt() bleibt der Zeilenumbruch stehen, deshalb braucht man ein zusätzliches nextLine() vor dem Lesen einer ganzen Zeile.
Serialisierung: JSON
Java hat kein eingebautes JSON. Üblich sind die Bibliotheken Jackson oder Gson:
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Person("Mia", 17)); // {"name":"Mia","alter":17}
Person p = mapper.readValue(json, Person.class);Merke
- Modern:
PathundFiles(readString,writeString,readAllLines,lines,walk) - Dateioperationen werfen
IOException(checked) - Große Dateien zeilenweise lesen (
BufferedReader,Files.lines), Ressourcen mit try-with-resources schließen Path.of(...),resolve,normalizestatt Zeichenketten für PfadeScannerliest Eingaben; für JSON Jackson oder Gson
Übungsaufgabe
Schreibe ein Programm, das eine Textdatei einliest, Wörter zählt und das Ergebnis in eine zweite Datei schreibt.
Quiz zur Selbstkontrolle
Welche Klasse bietet statische Methoden wie readString und writeString?
- java.nio.file.Files (richtig)
- java.io.File
- java.util.Scanner
- java.lang.System
Welche Ausnahme löst Dateizugriff aus?
- IOException (richtig)
- FileNotFound-Error
- DataError
- DiskException
Warum try-with-resources bei Dateien?
- Die Datei wird automatisch geschlossen (richtig)
- Dateien werden schneller gelesen
- Der Pfad wird geprüft
- Die Datei wird verschlüsselt
Weiter im Kurs
Zurück: Lambdas und Streams
Weiter: Datum und Zeit
Alle Kapitel: Java im Überblick