C-Programmier-Tutorial zum Umgang mit Dateien mit wahlfreiem Zugriff

Personen, die verschlüsselte Daten über Cloud Computing kommunizieren

Roy Scott/Getty Images





Abgesehen von den einfachsten Anwendungen müssen die meisten Programme Dateien lesen oder schreiben. Es kann nur zum Lesen einer Konfigurationsdatei oder eines Textparsers oder etwas Ausgefeilterem dienen. Dieses Tutorial konzentriert sich auf die Verwendung von Dateien mit wahlfreiem Zugriff in C.

Programmieren von Datei-E/A mit wahlfreiem Zugriff in C

Binärdatei

D3Damon/Getty Images



Die grundlegenden Dateioperationen sind:

  • fopen - eine Datei öffnen - angeben, wie sie geöffnet wird (Lesen/Schreiben) und Typ (Binär/Text)
  • fclose - schließt eine geöffnete Datei
  • fread - aus einer Datei lesen
  • fwrite - in eine Datei schreiben
  • fseek/fsetpos - verschiebt einen Dateizeiger irgendwo in einer Datei
  • ftell/fgetpos - teilt Ihnen mit, wo sich der Dateizeiger befindet

Die beiden grundlegenden Dateitypen sind Text und binär. Von diesen beiden sind Binärdateien normalerweise einfacher zu handhaben. Aus diesem Grund und der Tatsache, dass der wahlfreie Zugriff auf eine Textdatei nicht oft erforderlich ist, beschränkt sich dieses Tutorial auf Binärdateien. Die ersten vier oben aufgeführten Operationen gelten sowohl für Text- als auch für Direktzugriffsdateien. Die letzten beiden nur für wahlfreien Zugriff.



Wahlfreier Zugriff bedeutet, dass Sie zu einem beliebigen Teil einer Datei wechseln und Daten daraus lesen oder schreiben können, ohne die gesamte Datei lesen zu müssen. Vor Jahren wurden Daten auf großen Spulen von Computerbändern gespeichert. Die einzige Möglichkeit, zu einem Punkt auf dem Band zu gelangen, bestand darin, das Band ganz durchzulesen. Dann kamen Disketten und jetzt können Sie jeden Teil einer Datei direkt lesen.

Programmieren mit Binärdateien

Eine Binärdatei ist eine Datei beliebiger Länge, die Bytes mit Werten im Bereich von 0 bis 255 enthält. Diese Bytes haben keine andere Bedeutung als in einer Textdatei, wo ein Wert von 13 Wagenrücklauf, 10 Zeilenvorschub und 26 Zeilenende bedeutet Datei. Software, die Textdateien liest, muss sich mit diesen anderen Bedeutungen auseinandersetzen.

Binärdateien sind ein Strom von Bytes, und moderne Sprachen arbeiten eher mit Strömen als mit Dateien. Der wichtige Teil ist der Datenstrom und nicht, woher er kommt. ImC, können Sie sich die Daten entweder als Dateien oder Streams vorstellen. Mit wahlfreiem Zugriff können Sie jeden Teil der Datei oder des Streams lesen oder schreiben. Beim sequentiellen Zugriff müssen Sie die Datei oder den Stream von Anfang an wie ein großes Band durchlaufen.

Dieses Codebeispiel zeigt eine einfache Binärdatei, die zum Schreiben geöffnet wird und in die eine Textzeichenfolge (char *) geschrieben wird. Normalerweise sehen Sie dies bei einer Textdatei, aber Sie können Text in eine Binärdatei schreiben.



Dieses Beispiel öffnet eine Binärdatei zum Schreiben und schreibt dann ein char * (String) hinein. Die Variable FILE * wird vom fopen()-Aufruf zurückgegeben. Wenn dies fehlschlägt (die Datei könnte existieren und geöffnet oder schreibgeschützt sein oder es könnte ein Fehler mit dem Dateinamen vorliegen), wird 0 zurückgegeben.

Der Befehl fopen() versucht, die angegebene Datei zu öffnen. In diesem Fall ist es test.txt im selben Ordner wie die Anwendung. Wenn die Datei einen Pfad enthält, müssen alle Backslashes verdoppelt werden. 'c:Ordner est.txt' ist falsch; Sie müssen 'c:\Ordner\test.txt' verwenden.



Da der Dateimodus „wb“ ist, schreibt dieser Code in eine Binärdatei. Die Datei wird erstellt, wenn sie nicht existiert, und wenn sie existiert, wird alles, was darin enthalten war, gelöscht. Wenn der Aufruf von fopen fehlschlägt, vielleicht weil die Datei geöffnet war oder der Name ungültige Zeichen oder einen ungültigen Pfad enthält, gibt fopen den Wert 0 zurück.

Obwohl Sie einfach prüfen könnten, ob ft ungleich Null ist (Erfolg), hat dieses Beispiel eine FileSuccess()-Funktion, um dies explizit zu tun. Unter Windows gibt es den Erfolg/Fehler des Aufrufs und den Dateinamen aus. Es ist ein wenig lästig, wenn Sie auf Leistung aus sind, also können Sie dies auf das Debuggen beschränken. Unter Windows gibt es wenig Overhead, um Text an den Systemdebugger auszugeben.



Die Aufrufe von fwrite() geben den angegebenen Text aus. Der zweite und dritte Parameter sind die Größe der Zeichen und die Länge der Zeichenkette. Beide sind als size_t definiert, was eine vorzeichenlose Ganzzahl ist. Das Ergebnis dieses Aufrufs ist das Schreiben von count-Elementen der angegebenen Größe. Beachten Sie, dass bei Binärdateien, obwohl Sie eine Zeichenkette (char *) schreiben, keine Wagenrücklauf- oder Zeilenvorschubzeichen angehängt werden. Wenn Sie diese möchten, müssen Sie sie explizit in die Zeichenfolge aufnehmen.

Dateimodi zum Lesen und Schreiben von Dateien

Wenn Sie eine Datei öffnen, geben Sie an, wie sie geöffnet werden soll – ob sie neu erstellt oder überschrieben werden soll und ob es sich um Text- oder Binärdatei, Lese- oder Schreibdatei handelt und ob Sie etwas anhängen möchten. Dies erfolgt unter Verwendung eines oder mehrerer Dateimodusbezeichner, die aus den einzelnen Buchstaben 'r', 'b', 'w', 'a' und '+' in Kombination mit den anderen Buchstaben bestehen.



  • r - Öffnet die Datei zum Lesen. Dies schlägt fehl, wenn die Datei nicht vorhanden ist oder nicht gefunden werden kann.
  • w - Öffnet die Datei als leere Datei zum Schreiben. Wenn die Datei existiert, wird ihr Inhalt zerstört.
  • a – Öffnet die Datei zum Schreiben am Ende der Datei (Anhängen), ohne die EOF-Markierung zu entfernen, bevor neue Daten in die Datei geschrieben werden; Dadurch wird die Datei zuerst erstellt, wenn sie nicht existiert.

Durch das Hinzufügen von '+' zum Dateimodus werden drei neue Modi erstellt:

  • r+ - Öffnet die Datei sowohl zum Lesen als auch zum Schreiben. (Die Datei muss existieren.)
  • w+ - Öffnet die Datei als leere Datei zum Lesen und Schreiben. Wenn die Datei existiert, wird ihr Inhalt zerstört.
  • a+ - Öffnet die Datei zum Lesen und Anhängen; die Anhängeoperation umfasst das Entfernen der EOF-Markierung, bevor neue Daten in die Datei geschrieben werden, und die EOF-Markierung wird wiederhergestellt, nachdem das Schreiben abgeschlossen ist. Es erstellt die Datei zuerst, wenn sie nicht existiert. Öffnet die Datei zum Lesen und Anhängen; die Anhängeoperation umfasst das Entfernen der EOF-Markierung, bevor neue Daten in die Datei geschrieben werden, und die EOF-Markierung wird wiederhergestellt, nachdem das Schreiben abgeschlossen ist. Es erstellt die Datei zuerst, wenn sie nicht existiert.

Dateimodus-Kombinationen

Diese Tabelle zeigt Dateimoduskombinationen für Text- und Binärdateien. Im Allgemeinen lesen Sie entweder aus einer Textdatei oder schreiben in eine Textdatei, aber nicht beides gleichzeitig. Mit einer Binärdatei können Sie dieselbe Datei sowohl lesen als auch schreiben. Die folgende Tabelle zeigt, was Sie mit jeder Kombination machen können.

  • r-Text - lesen
  • rb+ binär - lesen
  • r+ text - lesen, schreiben
  • r+b binär - lesen, schreiben
  • rb+ binär - lesen, schreiben
  • w text - schreiben, erstellen, abschneiden
  • wb binär - schreiben, erstellen, abschneiden
  • w+ text - lesen, schreiben, erstellen, abschneiden
  • w+b binär - lesen, schreiben, erstellen, abschneiden
  • wb+ binär - lesen, schreiben, erstellen, abschneiden
  • ein text - schreiben, erstellen
  • ab binär - schreiben, erstellen
  • a+ text - lesen, schreiben, erstellen
  • a+b binär - schreiben, erstellen
  • ab+ binär - schreiben, erstellen

Sofern Sie nicht nur eine Datei erstellen (verwenden Sie „wb“) oder nur eine lesen (verwenden Sie „rb“), können Sie mit „w+b“ davonkommen.

Einige Implementierungen erlauben auch andere Buchstaben. Microsoft erlaubt zum Beispiel:

  • t - Textmodus
  • c - begehen
  • n - unverbindlich
  • S - Optimierung des Caching für sequenziellen Zugriff
  • R - Caching nicht sequentiell (wahlfreier Zugriff)
  • T - vorübergehend
  • D - delete/temporary, wodurch die Datei gelöscht wird, wenn sie geschlossen wird.

Diese sind nicht tragbar, verwenden Sie sie also auf eigene Gefahr.

Beispiel für die Speicherung von Dateien mit wahlfreiem Zugriff

Der Hauptgrund für die Verwendung von Binärdateien ist die Flexibilität, die es Ihnen ermöglicht, überall in der Datei zu lesen oder zu schreiben. Mit Textdateien können Sie nur sequentiell lesen oder schreiben. Mit der Verbreitung kostengünstiger oder kostenloser Datenbanken wie z SQLite undMySQL, reduziert die Notwendigkeit, wahlfreien Zugriff auf Binärdateien zu verwenden. Der wahlfreie Zugriff auf Dateiaufzeichnungen ist jedoch etwas altmodisch, aber immer noch nützlich.

Untersuchung eines Beispiels

Angenommen, das Beispiel zeigt ein Index- und Datendateipaar, das Zeichenfolgen in einer Datei mit wahlfreiem Zugriff speichert. Die Zeichenfolgen sind unterschiedlich lang und werden durch Position 0, 1 usw. indiziert.

Es gibt zwei void-Funktionen: CreateFiles() und ShowRecord(int recnum). CreateFiles verwendet einen char * -Puffer der Größe 1100, um eine temporäre Zeichenfolge zu speichern, die aus der Formatzeichenfolge msg gefolgt von n Sternchen besteht, wobei n zwischen 5 und 1004 variiert. Zwei FILE * werden beide mit wb filemode in den Variablen ftindex und ftdata erstellt. Nach der Erstellung werden diese verwendet, um die Dateien zu manipulieren. Die beiden Dateien sind

  • index.dat
  • Daten.dat

Die Indexdatei enthält 1000 Datensätze des Typs indextype; dies ist die Struktur indextype, die die beiden Member pos (vom Typ fpos_t) und size hat. Der erste Teil der Schleife:

füllt die Zeichenfolge msg wie folgt aus.

usw. Dann das:

füllt die Struktur mit der Länge der Zeichenfolge und der Stelle in der Datendatei, an der die Zeichenfolge geschrieben wird.

An diesem Punkt können sowohl die Indexdateistruktur als auch die Datendateizeichenfolge in ihre jeweiligen Dateien geschrieben werden. Obwohl es sich um Binärdateien handelt, werden sie sequentiell geschrieben. Theoretisch könnten Sie Datensätze an eine Position hinter dem aktuellen Dateiende schreiben, aber es ist keine gute Technik und wahrscheinlich überhaupt nicht portabel.

Der letzte Teil besteht darin, beide Dateien zu schließen. Dadurch wird sichergestellt, dass der letzte Teil der Datei auf die Festplatte geschrieben wird. Während Dateischreibvorgänge gehen viele der Schreibvorgänge nicht direkt auf die Festplatte, sondern werden in Puffern mit fester Größe gehalten. Nachdem ein Schreibvorgang den Puffer gefüllt hat, wird der gesamte Inhalt des Puffers auf die Festplatte geschrieben.

Eine Datei-Flush-Funktion erzwingt das Flushing, und Sie können auch Datei-Flushing-Strategien angeben, aber diese sind für Textdateien gedacht.

ShowRecord-Funktion

Um zu testen, ob ein bestimmter Datensatz aus der Datendatei abgerufen werden kann, müssen Sie zwei Dinge wissen: wo er in der Datendatei beginnt und wie groß er ist.

Das macht die Indexdatei. Die ShowRecord-Funktion öffnet beide Dateien, sucht an der entsprechenden Stelle (recnum * sizeof(indextype)) und holt eine Anzahl Bytes = sizeof(index).

SEEK_SET ist eine Konstante, die angibt, von wo aus fseek ausgeführt wird. Dafür sind zwei weitere Konstanten definiert.

  • SEEK_CUR - Suche relativ zur aktuellen Position
  • SEEK_END - sucht absolut vom Ende der Datei
  • SEEK_SET - sucht absolut vom Anfang der Datei

Sie könnten SEEK_CUR verwenden, um den Dateizeiger um sizeof(index) vorwärts zu bewegen.

Nachdem Sie die Größe und Position der Daten erhalten haben, müssen Sie sie nur noch abrufen.

Verwenden Sie hier fsetpos() wegen des Typs von index.pos, der fpos_t ist. Alternativ können Sie ftell anstelle von fgetpos und fsek anstelle von fgetpos verwenden. Das Paar fseek und ftell arbeitet mit int, während fgetpos und fsetpos fpos_t verwenden.

Nachdem der Datensatz in den Speicher gelesen wurde, wird ein Nullzeichen angehängt, um ihn in einen richtigen umzuwandeln C-Saite . Vergiss es nicht, sonst bekommst du einen Absturz. Wie zuvor wird fclose für beide Dateien aufgerufen. Obwohl Sie keine Daten verlieren, wenn Sie fclose vergessen (anders als beim Schreiben), haben Sie ein Speicherleck.