fs und io: Dateien und Byteübertragungen
Beschreibt die Dateilebensdauer, den vollständigen Lesevorgang, die teilweise Übertragung und den Status nach einem Fehler.
Wave Foundation
Datei API auswählen
Die Komfortfunktion von std::fs::file empfängt den Weg und führt das notwendige Öffnen und Schließen durch. Funktionen, die einen Deskriptor zurückgeben, müssen vom Aufrufer geschlossen werden.
| Erklärung | Erfolgsergebnisse und Vorsichtsmaßnahmen |
|---|---|
open_read(path: str) -> i64 |
Deskriptor öffnen. Negative Zahlen sind Fehler |
create(path: str) -> i64 |
Erstellen oder löschen Sie vorhandene Dateiinhalte. Gibt den besitzenden Deskriptor zurück |
open_append(path: str) -> i64 |
Zum Hinzufügen öffnen oder erstellen |
size(path: str) -> i64 |
Anzahl der Bytes. Negative Zahlen sind Fehler |
read_into(path: str, dst: ptr<u8>, dst_cap: i64) -> i64 |
Anzahl der Bytes in der gesamten Datei. Mangelnde Kapazität ist ein Fehler |
read_to_end(path: str, dst_buffer: ptr<Buffer>) -> i64 |
Fügen Sie die Datei nach dem vorhandenen Buffer hinzu und geben Sie den zusätzlichen Betrag zurück |
write(path: str, src: ptr<u8>, len: i64) -> i64 |
Anzahl der geschriebenen Bytes, die vorhandenen Inhalt ersetzen |
append(path: str, src: ptr<u8>, len: i64) -> i64 |
Anzahl der am Ende hinzugefügten Bytes |
remove(path: str) -> i64 |
Entfernungsstatus. Scheitern ist negativ |
false von exists(path) allein kann nicht zwischen fehlenden Dateien und Berechtigungsfehlern unterscheiden. Überprüfen Sie unbedingt das tatsächliche Öffnungsergebnis, da sich der Status zwischen der Prüfung auf Existenz und dem Öffnen ändern kann.
Niedriges Niveau I/O
std::io::fd
io_read(fd: i64, buf: ptr<u8>, len: i64) -> i64
io_write(fd: i64, buf: ptr<u8>, len: i64) -> i64
io_read_exact(fd: i64, buf: ptr<u8>, len: i64) -> i64
io_write_all(fd: i64, buf: ptr<u8>, len: i64) -> i64
io_close(fd: i64) -> i64
Das positive Ergebnis von io_read ist die Anzahl der gelesenen Bytes, und 0 in einer Anfrage mit positiver Länge ist EOF. io_write kann weniger als angefordert geschrieben werden. Wenn eine vollständige Übertragung erforderlich ist, verwenden Sie die Funktion exact/all. Dennoch gehen wir nicht davon aus, dass der Fehler den externen Status wiederherstellt, da einige Übertragungen möglicherweise bereits vor dem Fehler stattgefunden haben.
io_read_exact ist ein Fehler, wenn EOF vor der erforderlichen Länge auftritt. read_into gibt IO_ERR_NO_SPACE zurück, wenn der Puffer voll ist und möglicherweise bereits einige Bytes geschrieben wurden. Die Lesefunktion hängt NUL nicht automatisch an das Ende der Zeichenfolge an.
Buffer und Fehlerbehandlung
Bei einem Fehler stellt read_to_end die ursprüngliche Länge wieder her, aber ihre Kapazität und Datenadresse haben sich möglicherweise geändert. Der Anrufer muss den Buffer nach Erfolg oder Misserfolg freigeben. APIs zum Schreiben von Dateien garantieren keine atomare Dateiersetzung.
Ab Übung zum Lesen von Dateien können Sie das Programm von import bis zur Veröffentlichung ausführen. Berücksichtigen Sie die Pfad-/Berechtigungsunterschiede in Linux/macOS/Windows/FreeBSD und die Einschränkungen für zugängliche Verzeichnisse in WASI. Der Deskriptorwert wird nicht direkt als Rohhandle eines anderen OS interpretiert.
Große Dateien in kleine Puffer einlesen
Vorgänge, bei denen nicht die gesamte Datei im Speicher abgelegt werden muss, können mit festen Puffern und Leseiterationen verarbeitet werden. Das folgende Programm druckt den Inhalt von input.txt und zählt die Gesamtzahl der gelesenen Bytes. Speichern Sie ein Wave und ein LF in der Eingabedatei.
import("std::fs::file")::{open_read};
import("std::io::fd")::{io_read, io_write_all, io_close};
import("std::io::consts")::{IO_STDOUT_FD};
fun main() -> i32 {
var descriptor: i64 = open_read("input.txt");
if (descriptor < 0) {
return 1;
}
var buffer: array<u8, 4>;
var total: i64 = 0;
while (true) {
var count: i64 = io_read(descriptor, &buffer[0], 4);
if (count < 0) {
io_close(descriptor);
return 2;
}
if (count == 0) {
break;
}
if (io_write_all(IO_STDOUT_FD, &buffer[0], count) < 0) {
io_close(descriptor);
return 3;
}
total += count;
}
if (io_close(descriptor) < 0) {
return 4;
}
println("bytes={}", total);
return 0;
}
Ausführungsergebnis:
Wave
bytes=5
Die Pufferkapazität beträgt 4, aber der letzte Lesevorgang kann 1 Byte umfassen. Wir übergeben immer den tatsächlichen count an die Ausgabe. Wenn Sie das gesamte Array schreiben, können auch alte, ungelesene Bytes ausgegeben werden.
Das Programm hat descriptor von input.txt geöffnet, also schließen Sie es. Die Standardausgabe ist in dieser Funktion keine neu erworbene Ressource und wird daher am Ende des Beispiels nicht willkürlich geschlossen.
Vollständige Lesevorgänge und unzureichende Kapazität
read_into erhält einen festen Speicherplatz, der die gesamte Datei enthält. Wenn der Platz nicht ausreicht, wird der Text stillschweigend abgeschnitten und NO_SPACE ohne Erfolg zurückgegeben.
import("std::fs::file")::{read_into};
import("std::io::consts")::{IO_ERR_NO_SPACE};
fun main() {
var data: array<u8, 2>;
var status: i64 = read_into("input.txt", &data[0], 2);
if (status == IO_ERR_NO_SPACE) {
println("destination too small");
}
}
Ausführungsergebnis:
destination too small
Es wird nicht davon ausgegangen, dass der fehlgeschlagene Lesevorgang das Zielbyte überhaupt nicht geändert hat. Verwenden Sie es nicht als fertigen Dateiinhalt, bereiten Sie ein größeres Repository vor oder wählen Sie die Methode streaming. Selbst wenn Sie zuerst die Größe abfragen, ist das tatsächliche Leseergebnis die endgültige Beurteilung, da sich die Datei zwischen Abfrage und Lesevorgang ändern kann.
Unterschied zwischen Schreiben und Anhängen von Dateien
write ersetzt den vorhandenen Inhalt und append wird am Ende hinzugefügt. Die Anzahl der zu speichernden Bytes kann direkt aus der Stringlänge ermittelt und übergeben werden. Das NUL am Ende der Zeichenfolge ist normalerweise nicht im Inhalt der Textdatei enthalten.
import("std::fs::file")::{write, append, size, remove};
import("std::string::len")::{len};
fun main() -> i32 {
var first: str = "Wave";
var second: str = " study";
if (write("output.txt", first as ptr<u8>, len(first) as i64) < 0) {
return 1;
}
if (append("output.txt", second as ptr<u8>, len(second) as i64) < 0) {
return 2;
}
println("bytes={}", size("output.txt"));
if (remove("output.txt") < 0) {
return 3;
}
return 0;
}
Ausführungsergebnis:
bytes=10
In diesem Beispiel wird output.txt im Arbeitsverzeichnis erstellt, ersetzt und schließlich gelöscht. Vom Übungsverzeichnis aus ausführen, ohne dass Dateien vorhanden sind. Für den eigentlichen Editor oder das Speicherprogramm sind möglicherweise separate Speicherrichtlinien erforderlich, z. B. für temporäre Dateien und Ersatz.
API Auswahltabelle
| Situation | auswählen |
|---|---|
| Kleine gesamte Datei in festen Puffer einlesen | read_into |
| Behalten Sie den gesamten Inhalt, ohne die Größe zu kennen | read_to_end und Buffer |
| Verarbeiten Sie Inhalte der Reihe nach, anstatt sie vollständig zu speichern | open_read + io_read wiederholen |
| Datensätze mit fester Länge lesen | io_read_exact |
| Gesamte Bytefolge übertragen | io_write_all |
| Umgang mit bereits geöffneten Dateien | fd-Funktion statt Pfadfunktion |
Überprüfen Sie nach Auswahl einer Funktion, wie sich Puffer, Dateispeicherort und externe Daten im Fehlerfall ändern.