C: Der beste Weg, um zu einer bekannten Zeile einer Datei zu gelangen

8

Ich habe eine Datei, in der ich ohne eine Verarbeitung der aktuellen Zeile iterieren möchte. Nach was ich suche, ist der beste Weg, zu einer bestimmten Zeile einer Textdatei zu gehen. Zum Beispiel scheint das Speichern der aktuellen Zeile in einer Variablen nutzlos, bis ich die vorher festgelegte Zeile erreiche.

Beispiel:

Datei.txt

%Vor%

Normalerweise, um here zu erhalten, hätte ich etwas wie folgt gemacht:

%Vor%

Aber fgets muss drei Zeile sinnlos lesen und currentLine muss foo , fooo und fo speichern.

Gibt es einen besseren Weg dies zu tun, wenn man weiß, dass here Zeile 4 ist? Etwas wie ein go to , aber für Dateien?

    
Badda 29.05.2017, 14:10
quelle

4 Antworten

5

Sie können nicht direkt auf eine bestimmte Zeile einer Textdatei zugreifen (es sei denn, alle Zeilen haben die gleiche Größe in Bytes und UTF8 überall ein Unicode-Zeichen kann eine variable Anzahl von Bytes annehmen, 1 bis 6. In den meisten Fällen haben Zeilen unterschiedliche Länge - verschieden von einer Zeile zur nächsten. Sie können also fseek nicht verwenden (weil Sie den Dateiversatz nicht im Voraus kennen).

>

Allerdings enden Zeilen (zumindest auf Linux-Systemen) mit \n (dem Newline-Zeichen). So könnten Sie byteweise lesen und zählen:

%Vor%

Sie müssen dann nicht die gesamte Zeile speichern.

Sie könnten also auf diese Weise die Zeile 45 erreichen (mit while ((c=fgetc(file)) != EOF) && linecount<45) ...) und erst dann ganze Zeilen mit fgets oder besser lesen, noch getline (3) auf POSIX-Systemen (siehe dies Beispiel). Beachten Sie, dass die Implementierung von fgets oder getline wahrscheinlich oberhalb von fgetc erstellt wird oder zumindest etwas Code mit ihr teilt. Denken Sie daran, dass <stdio.h> gepuffert ist, siehe setvbuf (3 ) und verwandte Funktionen.

Ein anderer Weg wäre, die Datei in zwei Durchgängen zu lesen. Ein erster Durchlauf speichert den Offset (unter Verwendung von ftell (3) ...) von jedem Zeilenanfang in einer effizienten Datenstruktur (ein Vektor, eine Hashtabelle, ein Baum ...). Ein zweiter Durchlauf verwendet diese Datenstruktur, um den Offset (des Zeilenanfangs) abzurufen. Verwenden Sie dann fseek ( 3) (mit diesem Offset).

Ein dritter, POSIX-spezifischer Weg wäre, die Datei mit mmap (2 ) in Ihren virtuellen Adressraum (dies funktioniert gut für nicht zu große Dateien, zB von weniger als einigen Gigabyte). Vorsicht (Sie müssen möglicherweise mmap eine extra Endseite eingeben, um sicherzustellen, dass die Daten mit Nullbyte abgeschlossen sind), dann können Sie strchr (3) mit '\n'

PS. BTW, der Begriff der Linien (und die End-of-Line-Marke) variieren von einem Betriebssystem zum nächsten. Unter Linux ist das Ende der Zeile ein \n -Zeichen. Auf Windows-Zeilen wird gemunkelt, dass sie mit \r\n usw. enden ...

    
Basile Starynkevitch 29.05.2017, 14:20
quelle
8

Da Sie die Länge jeder Zeile nicht kennen, no , müssen Sie die vorherigen Zeilen durchgehen.

Wenn Sie die Länge jeder Zeile kennen, könnten Sie wahrscheinlich mit der Anzahl der Bytes spielen, um den Dateizeiger zu verschieben. Sie könnten dies mit fseek() tun.

    
gsamaras 29.05.2017 14:12
quelle
5

A FILE * in C ist ein Stream von char s. In einer suchbaren Datei können Sie diese char s mit dem Dateizeiger mit fseek() adressieren. Aber abgesehen davon gibt es keine "Sonderzeichen" in Dateien, ein Newline ist nur ein anderes normales Zeichen.

Kurz gesagt, nein, Sie können nicht direkt zu einer Zeile einer Textdatei springen, solange Sie die Längen der Zeilen nicht im Voraus kennen.

Dieses Modell in C entspricht den Dateien, die von typischen Betriebssystemen bereitgestellt werden. Wenn Sie darüber nachdenken, die Startpunkte einzelner Zeilen zu kennen, müsste Ihr Dateisystem diese Informationen irgendwo speichern. Dies würde bedeuten, Textdateien speziell zu behandeln.

Was Sie tun können , zählt jedoch nur die Zeilen anstelle des Mustervergleichs, etwa so:

%Vor%     
Felix Palmen 29.05.2017 14:25
quelle
1

Wenn Sie die Länge jeder Zeile nicht kennen, müssen Sie alle durchgehen. Aber wenn du die Zeile kennst, die du anhalten willst, kannst du das tun:

%Vor%

Zumindest können Sie so viele Aufrufe von strstr

vermeiden     
Jesferman 29.05.2017 14:20
quelle

Tags und Links