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));
}
}[Zeile 1, Zeile 2, Zeile 3] 24 true 24 notiz.txt kopie.txt notiz.txt false
Alle 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);
}
}Summe der Alter: 57 2 neu
Gib 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());
}
}ordner/unter/bild.png bild.png ordner/unter 3 /a/c/d c/d true false
Ordner 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));
}
}a/b/zwei.txt a/eins.txt false
Eingabe 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());
}
}Mia 17 3.5 | ein ganzer Satz false
Im 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
Aufgabe
Schreibe ein Programm, das eine Textdatei einliest, Wörter zählt und das Ergebnis in eine zweite Datei schreibt.