Dateien lesen und schreiben in Rust 1.x: De-facto-Ansätze

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Rust und Dateien: Mythen, Ängste und De-facto-Ansätze

Haben Sie sich jemals gefragt: „Wie liest und schreibt man eigentlich richtig Dateien in modernem Rust?“ Wenn ja, sind Sie nicht allein. Auf Stack Overflow hat die Frage „What's the de-facto way of reading and writing files in Rust 1.x?“ tausende Aufrufe und Dutzende Antworten gesammelt. Das ist ein echter Schmerzpunkt der Community, besonders für diejenigen, die von Python oder JavaScript kommen, wo open() und read() die Grundlage sind, während man sich in Rust mit Ownership, Borrowing und einer Vielzahl von Traits auseinandersetzen muss.

In diesem Artikel ordnen wir alle grundlegenden Methoden zur Dateiarbeit in Rust 1.x systematisch ein: von „einfach alles in einen String lesen“ bis zum effizienten zeilenweisen Lesen großer Logdateien. Sie erfahren, welcher Ansatz als idiomatisch gilt und welchen Sie besser für besondere Fälle aufheben sollten. Los geht's!



1. std::fs: Das Standard-Arsenal

Das Modul std::fs ist Ihre erste Anlaufstelle. Es bietet Funktionen zum Lesen, Schreiben, Kopieren und Löschen von Dateien. Rust 1.x hat praktische Wrapper stabilisiert, die den Großteil der Low-Level-Arbeit mit Systemaufrufen verbergen.



Gesamte Datei in einen String lesen

Der einfachste Weg ist die Verwendung von std::fs::read_to_string. Es öffnet die Datei, liest sie vollständig in den Speicher und gibt ein Result<String> zurück. Ideal für kleine Konfigurationsdateien oder Textdateien.

use std::fs;

fn main() -> std::io::Result<()> { let content = fs::read_to_string("hello.txt")?; println!("Die Datei enthält:{}", content); Ok(())}

Diese Methode ist der De-facto-Standard für einfache Fälle. Sie ist prägnant, sicher und verwendet ? zur Fehlerbehandlung. Der einzige Nachteil: Die gesamte Datei wird in den Speicher geladen, daher ist sie für gigabytegroße Logdateien ungeeignet.



In einen Byte-Vektor lesen

Wenn Sie mit Binärdaten (Bilder, Archive) arbeiten, verwenden Sie std::fs::read. Es gibt ein Vec<u8> zurück.

use std::fs;

fn main() -> std::io::Result<()> { let bytes = fs::read("image.png")?; println!("{} Bytes gelesen", bytes.len()); Ok(())}


In eine Datei schreiben

Zum Schreiben verwenden Sie std::fs::write. Es akzeptiert einen Pfad und Daten (String oder Byte-Array) und erstellt/überschreibt die Datei.

use std::fs;

fn main() -> std::io::Result<()> { fs::write("output.txt", "Hallo, Rust!")?; Ok(())}

Einfach wie Kinderkram. Aber wenn Sie an das Ende einer Datei anhängen möchten, statt sie zu überschreiben, müssen Sie OpenOptions verwenden.



2. BufReader und BufWriter: Wenn die Größe zählt

Für große Dateien oder häufige E/A-Operationen helfen gepufferte Wrapper. Sie reduzieren die Anzahl der Systemaufrufe, was für die Leistung entscheidend ist.



Zeilenweises Lesen mit BufReader

Ein klassisches Beispiel ist das zeilenweise Lesen einer großen Logdatei:

use std::fs::File;use std::io::{BufRead, BufReader};

fn main() -> std::io::Result<()> { let file = File::open("large_log.txt")?; let reader = BufReader::new(file);

for line in reader.lines() { let line = line?; println!("{}", line); } Ok(())}

Die Methode lines() gibt einen Iterator über Zeilen zurück, von denen jede ein Result<String> ist. Beachten Sie das line? innerhalb der Schleife – dies dient der Fehlerbehandlung beim Lesen jeder Zeile.

Wichtig: lines() entfernt Zeilenumbruchzeichen. Wenn Sie diese behalten müssen, verwenden Sie read_until oder lesen Sie die Datei als Vec<u8>.



Schreiben mit BufWriter

Beim Schreiben großer Datenmengen ist Pufferung ebenfalls nützlich:

use std::fs::File;use std::io::{BufWriter, Write};

fn main() -> std::io::Result<

Blogs

Buchempfehlungen