[FILE*] Wie auf _ptr zugreifen?
-
Kurze Frage:
Wie kann ich auf _ptr eines FILE Pointers zugreifen, wenn noch keine Daten per fread eingelesen wurden ?
Zur Erläuterung:FILE *fp_indata; [...] fp_indata = fopen("testdaten.txt", "rb"); [...] fread ( buffer, sizeof(char), strcspn( fp_indata->_ptr, "\n"), fp_indata);
Würde gerne per strcspn und fread Zeilenweise Daten einlesen.
-
Was du da tust ist hochgradig unportabel, das hängt also von der Implementation deiner stdio-Library ab.
Funktioniert das denn überhaupt? Ich nehm mal an _ptr zeigt auf den privaten Buffer des FILEs. Was machst du, wenn eine Zeile länger als der Buffer ist?
Was spricht eigentlich gegen fgets? Dass deine Frickelei performanter sein soll oder sonst irgendeinen Vorteil hat kann ich nämlich gerade nicht erkennen.
-
Gut. Sofort verwerfen die Idee. An fgets hab ich jetz mal garnicht gedacht ...
Wie kann ich denn die Länge der Zeile vor dem Einlesen feststellen ?
-
Pyro Phoenix schrieb:
Wie kann ich denn die Länge der Zeile vor dem Einlesen feststellen ?
Geht nur mit einer Kristallkugel.
Denn bevor du dir die Daten nicht angesehen hast, kannst du nicht wissen wieviele es sind.Du kannst aber mit fgets() oder aber auf fgetc() solange einlesen bis ein \n kommt...
-
Ich muss doch irgendwie die Größe des Buffers festlegen, bevor ich damit anfange, die Zeilen dort hineinzulesen.
Wie mach ich das denn am Besten ?
-
Du kannst auch jedesmal, wenn du merkst, dass dein Buffer zu klein ist, ihn mit realloc() vergrößern (z.B. verdoppeln). Wenn du magst kannst du ihn dann am Ende nochmal auf die richtige Größe zurechtstutzen.
-
Klingt nach zuviel overhead.
Würde das eigentlich gerne möglichst effizient regeln.
Undzwar sollen die Zeilen direkt als strings in eine LinkedList geladen werden.struct Line { unsigned char *sz_string; struct Line *next; struct Line *prev; };
-
Effizienter geht es aber nicht.
-
du könntest auch GNU getline verwenden: http://www.gnu.org/software/hello/manual/libc/Line-Input.html
-
Auf fertige Dinge wollte nich noch nicht zurückgreifen.
Also tehoretisch müsste ich lediglich Zeichen für Zeichen einlesen, und den Buffer jedes mal um 1 char erhöhen, bis ein newline Zeichen eingelesen wird. Statt newline wird der buffer dann nullterminiert.
Und das wird dann so lange wiederholt, bis EOF.
Könnte das so hinhaun ?
-
Ja, das funktioniert, aber es wäre sehr langsam. Vergrößere den Puffer immer um mindesten 100 Zeichen oder so, je nachdem wie lang eine Zeile durchschnittlich ist. Ansonsten musst du ja extremst viele Daten hin und her schieben, bzw realloc schiebt sie hin und her.
-
Und wenn man den Puffer nicht jeweils um eine bestimmte Anzahl Bytes, sondern um einen bestimmten Faktor vergrößert (z.B. verdoppelt), ist der Aufwand selbst dann noch linear, wenn bei jedem realloc der Puffer kopiert wird.
-
Pyro Phoenix schrieb:
Klingt nach zuviel overhead.
Würde das eigentlich gerne möglichst effizient regeln.
Undzwar sollen die Zeilen direkt als strings in eine LinkedList geladen werden.struct Line { unsigned char *sz_string; struct Line *next; struct Line *prev; };
Du kannst du dich nach einer getline-ähnliche Implementierung http://www.c-plusplus.net/forum/viewtopic-var-p-is-1686949.html#1686949 keine effiziente Implementierung (siehe namespaces Beitrag) aber zumindet ein Anhaltspunkt für dich.
Auf fertige Dinge wollte nich noch nicht zurückgreifen.
man sollte nicht das Rad neu erfinden
-
Ich hab das jetzt so geregelt:
#include <stdio.h> #include <string.h> struct Line { unsigned char *sz_string; struct Line *next; struct Line *prev; }; int main (int argv, char *argc[], char *envp[]) { FILE *fp_indata; unsigned char *sz_buffer; Line *root, *actv; fpos_t actfile = 0; fpos_t firstchar = 0; fpos_t lastchar = 0; root = new struct Line; root->prev = NULL; root->next = NULL; root->sz_string = NULL; sz_buffer = new unsigned char[2]; sz_buffer[1] = NULL; if ( ( fp_indata = fopen("C:\\testdaten.txt", "rb") ) == NULL ) { printf("File not found.\n"); } else { actv = root; while ( !feof(fp_indata) ) { fsetpos (fp_indata, &actfile); firstchar = actfile; while ( *sz_buffer >= 0x20 ) { fread ( sz_buffer, sizeof(unsigned char), 1, fp_indata); actfile++; }; lastchar = actfile -1; while ( *sz_buffer <= 0x0F ) { fread ( sz_buffer, sizeof(unsigned char), 1, fp_indata); actfile++; }; fsetpos (fp_indata, &firstchar); actv->sz_string = new unsigned char [(long)(lastchar-firstchar)]; fread (actv->sz_string, sizeof(unsigned char), (long)(lastchar-firstchar), fp_indata); actv->sz_string[(long)(lastchar-firstchar)] = 0x00; if ( !feof(fp_indata) ) { actv->next = new struct Line; actv->next->prev = actv; actv = actv->next; actv->next = NULL; actv->sz_string = NULL; } actfile--; } } fclose (fp_indata); return 0; }
Aber nach dem 2. Durchlauf der Schleife habe ich plötzlich Probleme mit dem FILE Pointer. Das äussert sich folgendermaßen:
Durchlauf 1:
http://img18.imageshack.us/img18/8938/capture08042009005024.jpg
Durchlauf 2:
http://img19.imageshack.us/img19/5940/capture08042009005032.jpg
Durchlauf 3:
http://img16.imageshack.us/img16/1306/capture08042009005047.jpg
testdaten.txt
Hallo Welt ! Dies ist eine Testdatei ! EOF
Woran liegt das, das der plötzlich verrückt spielt ?
Mag der das setpos nicht oder wie ?
-
Pyro Phoenix schrieb:
#include <stdio.h> #include <string.h> ... root = new struct Line; ... actv->next = new struct Line; ... }
igit.... häßliche Mischung von C und C++. Entweder C oder C++ aber nicht beide!
-
Das behebt das Problem leider auch nicht.
-
Das fsetpos in Zeile 40 muss fgetpos sein.
Ansonsten schließe ich mich der Meinung von supertux an.
Und das Rumrechnen mit fpos_t ist nicht portabel, das könnte nämlich auch eine Struktur sein. Du solltest die Stringlänge lieber in einem Integer (oder besser size_t) zählen.
-
zu dem Code fällt mir nur eins: wieso einfacher, wenn es schwieriger geht
-
Pyro Phoenix schrieb:
Klingt nach zuviel overhead.
Würde das eigentlich gerne möglichst effizient regeln.Der Overhead dabei ist logarithmisch, d.h. absolut in Ordnun aus Informatiksicht. Und wenn du den selben Buffer für jede Zeile benutzt, dann kannst du den Overhead noch durch die Anzahl der Zeilen teilen und kommst dann auf einen sehr kleinen Overhead auf die gesamte Datei gerechnet.
Alternativ benutzt du eine Liste welche deine Buffer enthält und jedes mal wenn der Buffer am Ende voll ist erzeugst du einen neuen mit N Bytes Platz und hängst ihn hinten an. So wäre der Speicherverbrauch geringer bei einer Datei mit 2^n+m Zeichen, wobei m deutlich kleiner als 2^n sein sollte (z.B. m=1 und bei großem n auch noch m=1000).
-
Nach sovielen Tipps hab ich nun echt keine Ahnung mehr, wie ich das regeln soll. Der eine meckert über meinen Programmierstil - was ich durchaus nachvollziehen kann - und der nächste gibt einem Tipps, mit denen ein Laie nix anzufangen weiß.
namespace invader schrieb:
Das fsetpos in Zeile 40 muss fgetpos sein.
Ne eben nicht, weil sonst wieder ein Newline Zeichen eingelesen wird - und das ganze dann in einer Endlosschleife endet.