Einführung
Viele nützliche Programme überschreiten eine Dateisystemgrenze: Sie lesen vorhandene Daten, verarbeiten sie und speichern ein Ergebnis. Diese Vorgänge können fehlschlagen. Deshalb geben Rusts Datei-APIs Result-Werte zurück, anstatt einen garantierten Erfolg vorzutäuschen.
Sie untersuchen ein vorbereitetes Serviceprotokoll, stellen Dateipfade mit Path dar, lesen Text mit std::fs, erstellen eine kleine Zusammenfassung, schreiben sie in eine andere Datei und leiten E/A-Fehler mit ? weiter.
Eine Textdatei über einen Path lesen
In diesem Schritt untersuchen Sie ein vorbereitetes Protokoll und lesen es in einen Rust-String ein.
Das Projekt befindet sich unter /home/labex/project/log-summary. Es enthält data/events.log als Eingabe, ein leeres Verzeichnis output für den späteren Bericht und src/main.rs als Programmquelle. Wechseln Sie in das Projektverzeichnis:
cd /home/labex/project/log-summary
Öffnen Sie die Eingabedatei mit nano, damit Sie wissen, was das Programm lesen wird:
nano data/events.log
Die Datei enthält drei kurze Einträge. Ändern Sie die Datei nicht. Drücken Sie Ctrl+X, um nano zu beenden. Öffnen Sie nun die Rust-Quelldatei:
nano src/main.rs
Die beiden vorbereiteten use-Zeilen machen die Dateifunktionen von std::fs und den Typ Path unter kurzen Namen verfügbar. Sie dienen lediglich als Importvorbereitung und sind nicht das Hauptthema dieses Labs. Das spätere Modul erklärt Pfade und use-Deklarationen ausführlich. Der Rückgabetyp std::io::Result<()> bedeutet, dass main entweder mit dem leeren Erfolgswert () abgeschlossen wird oder einen E/A-Fehler zurückgibt. Das abschließende Ok(()) stellt den erfolgreichen Abschluss dar.
Ersetzen Sie den Kommentar für Schritt 1 durch:
let input_path = Path::new("data/events.log");
let contents = fs::read_to_string(input_path)?;
println!("Input: {}", input_path.display());
println!("Contents:\n{}", contents.trim_end());
Path::new erstellt eine geliehene Ansicht eines Dateisystempfads, ohne etwas zu öffnen. Der relative Pfad wird ausgehend vom Projektverzeichnis aufgelöst, in dem Sie Cargo ausführen. fs::read_to_string öffnet die Datei, liest UTF-8-Text in einen eigenen String ein und gibt ein Result zurück. Bei Erfolg liefert ? den String; andernfalls gibt es den E/A-Fehler aus main zurück. display() formatiert einen Pfad für die Ausgabe an Menschen. trim_end() verhindert, dass der abschließende Zeilenumbruch der Datei eine zusätzliche leere Ausgabezeile erzeugt.
Speichern Sie mit Ctrl+O, drücken Sie Enter und beenden Sie nano mit Ctrl+X. Prüfen und starten Sie das Programm:
cargo check
cargo run --quiet
Input: data/events.log
Contents:
INFO service started
WARN disk nearing limit
INFO backup complete
Der angezeigte Pfad und alle drei Einträge bestätigen, dass das Programm die vorgesehene Datei gelesen hat.
Datensätze im geladenen Text zählen
In diesem Schritt zählen Sie die logischen Zeilen des bereits im Speicher befindlichen String.
Die Methode lines() erstellt einen Iterator über Textzeilen, ohne den Quell-String zu verändern. Der Verbraucher count() gibt zurück, wie viele Elemente der Iterator erzeugt hat. Öffnen Sie die Quelldatei:
nano src/main.rs
Ersetzen Sie den Kommentar für Schritt 2 durch:
let line_count = contents.lines().count();
println!("Line count: {line_count}");
Speichern und beenden Sie nano. Führen Sie anschließend das Programm aus:
cargo run --quiet
Die neue letzte Zeile sollte lauten:
Line count: 3
Dies funktioniert unabhängig davon, ob die Eingabe mit einem Zeilenumbruch endet, weil lines() logische Datensätze erkennt und nicht die Anzahl der Zeilenumbruch-Bytes zählt.
Eine stabile Zusammenfassungszeichenkette erstellen
In diesem Schritt zählen Sie Warnungseinträge und formatieren beide Zähler als Text, der gespeichert werden kann.
Die String-Methode starts_with prüft ein Präfix. In Kombination mit den Iterator-Adaptern, die Sie bereits kennen, kann das Programm nur die Zeilen zählen, die mit WARN beginnen. Öffnen Sie die Quelldatei:
nano src/main.rs
Ersetzen Sie den Kommentar für Schritt 3 durch:
let warning_count = contents
.lines()
.filter(|line| line.starts_with("WARN"))
.count();
let summary = format!("lines: {line_count}\nwarnings: {warning_count}\n");
println!("Summary ready:\n{}", summary.trim_end());
Das Filterprädikat behält Warnungszeilen bei, und count() verarbeitet diesen gefilterten Iterator. format! gibt einen neuen String zurück, anstatt ihn auszugeben. Die expliziten \n-Zeichen erzeugen zwei Zeilen und lassen einen abschließenden Zeilenumbruch stehen, der für eine Textdatei geeignet ist.
Speichern und beenden Sie nano. Prüfen und starten Sie anschließend das Programm:
cargo check
cargo run --quiet
Der letzte Abschnitt sollte lauten:
Summary ready:
lines: 3
warnings: 1
Die Zusammenfassung liegt nun als Daten im Speicher vor und kann an die Dateisystemgrenze geschrieben werden.
Die Zusammenfassungsdatei schreiben und erneut lesen
In diesem Schritt schreiben Sie die Zusammenfassung in das vorbereitete Ausgabeverzeichnis und lesen sie als Nachweis wieder ein.
fs::write(path, data) erstellt eine Datei oder ersetzt ihren bisherigen Inhalt vollständig durch die bereitgestellten Bytes. Die Funktion hängt die Daten nicht an den vorhandenen Inhalt an. Wie beim Lesen kann auch das Schreiben fehlschlagen und gibt ein E/A-Result zurück. Deshalb leiten Sie den Fehler mit ? weiter. Öffnen Sie die Quelldatei:
nano src/main.rs
Ersetzen Sie den Kommentar für Schritt 4 durch:
let output_path = Path::new("output/summary.txt");
fs::write(output_path, &summary)?;
let saved = fs::read_to_string(output_path)?;
println!("Saved {}:\n{}", output_path.display(), saved.trim_end());
&summary leiht die Zusammenfassung aus, während write ihre Bytes liest. Dadurch bleibt der String im Besitz des Programms. Das erneute Lesen der Datei prüft das tatsächlich gespeicherte Ergebnis, statt lediglich anzunehmen, dass der Schreibvorgang erfolgreich war.
Speichern und beenden Sie nano. Prüfen und starten Sie anschließend das Programm:
cargo check
cargo run --quiet
Der letzte Abschnitt sollte lauten:
Saved output/summary.txt:
lines: 3
warnings: 1
Öffnen Sie die erstellte Datei zur abschließenden Kontrolle:
nano output/summary.txt
Sie sollten dieselben beiden Zusammenfassungszeilen sehen. Drücken Sie Ctrl+X, um nano ohne Änderungen zu beenden.
Zusammenfassung
Sie haben Dateipfade mit Path dargestellt, UTF-8-Text mit fs::read_to_string gelesen, E/A-Fehler mit ? weitergeleitet, geladene Datensätze zusammengefasst, das Ergebnis mit fs::write geschrieben und die gespeicherte Datei erneut gelesen, um ihren Inhalt zu bestätigen.


