Zeile in einer Datei editieren (ich schon wieder...)
-
Hallo alle zusammen!
Ich häng schon wieder am nächsten Problem...
Ich schreibe am Ende meiner Funktion alle ermittelten Daten in eine Datei. Die Daten haben dabei folgende Struktur:
Zählernummer|alter Z-Stand|neuer Z-Stand|Überlauf|abzulesende Stellen|OrtDie einzelnen Daten sind durch Leerzeichen getrennt.
Momentan gibt mein Programm die Daten immer ganz brav aus, schreibt allerdings für jeden Datensatz immer eine neue Zeile. Ich hätte das jetzt gerne so, dass er sich die Zeile mit der richtigen Nummer sucht und dann diese Zeile mit den neuen Daten überschreibt.Also aus z.B.:
QB0306004 001000 000000 0 4 Testblatt Zeile:1 VQ0577000 009000 000000 1 4 Testblatt Zeile:1 VR0508002 020000 000000 0 5 Testblatt Zeile:1 QB0306003 100000 000000 0 6 Testblatt Zeile:2 VQ0576000 900000 000000 1 6 Testblatt Zeile:2
soll folgendes werden, nachdem ich Zähler QB0306004 abgelesen hab (der NEUE Zählerstand wurde geändert):
QB0306004 001000 002000 0 4 Testblatt Zeile:1 VQ0577000 009000 000000 1 4 Testblatt Zeile:1 VR0508002 020000 000000 0 5 Testblatt Zeile:1 QB0306003 100000 000000 0 6 Testblatt Zeile:2 VQ0576000 900000 000000 1 6 Testblatt Zeile:2
In meiner Funktion "lookup" habe ich ja schon so ungefähr was ich brauche: Dort wird auch nach Zählernummer gesucht und danach die Daten des gefundenen Datensatzes ausgelesen. Mein Problem liegt nun in der Handhabung der Datei. Ich dachte mir das so, dass ich in der Funktion "collect_data" bevor in die Datei geschrieben wird (was jetzt ja noch am Ende geschieht), erstmal in der Datei (INV_FILE) nach der richtigen Zeile gesucht wird und dann die Zeile überschrieben wird. Der Zeiger müsste doch nach dem Suchen schon an der richtigen Stelle stehen, oder???
Wäre wie immer Super, wenn ihr mir helft!
Viele Grüße,
ChrisPS: Der Vollständigkeit halber habe ich mal wieder die beiden Funktionen angehängt:
/******************************************************************************* * void collect_data(void) NEU * * * * Funktion: Die collect_data Funktion bekommt eine Nummer von der Tastatur * * oder dem Scanner und ruft dann die lookup Funktion auf. Wird die Nummer * * gefunden, so werden zus„tzliche Informationen gezeigt. * * Wird die Nummer nicht gefunden, kann der Benutzer die Nummer anlegen * * * *******************************************************************************/ void collect_data(void) { int ks, rc; /* ks=Keystroke, rc=ReturnCharacter */ int collect_flag = 1; char file_buffer[95]; /* Puffer fr die Daten aus der Datei */ if((inv_file = fopen(INVFILE, "r+")) == NULL) /* L„sst sich die Datei ”ffnen ?? */ { /* Error... */ clrscr(); gotoxy(2,1); printf("Dateifehler"); delay(1000); /* Nachricht fr 2 Sekunden zeigen */ } while(collect_flag) { memset(zNr,0,sizeof(zNr)); /* Variablen werden mit Nullwerten gefllt */ memset(oldStd,0,sizeof(oldStd)); memset(newStd,0,sizeof(newStd)); memset(ueber,0,sizeof(ueber)); memset(anzSt,0,sizeof(anzSt)); memset(einbau,0,sizeof(einbau)); inv_menu(); /* Inventurmen zeigen */ rc = get_scan_input(zNr,10,7,1,0); /* Nummer einlesen */ if(rc == -1) /* ESC wurde gedrckt */ { collect_flag = 0; break; } /* Ende von if (rc) */ trim_spaces(zNr); if(*zNr) /* Suchen und Finden... */ { if(lookup()) /* Nummer in der Datei suchen Variablen setzen */ { /* Z„hlernummer gefunden, Daten ausgeben: */ gotoxy(14,2); printf("%s",oldStd); gotoxy(10,4); printf("%s", anzSt); if(strcmp(ueber,"1") == 0) { gotoxy(13,4); printf("šberlauf"); } gotoxy(1,6); printf("%s",einbau); gotoxy(14,3); shift_lock(1); if(strcmp(newStd, "000000") != 0) /* Neuer ZS wurde schon eingegeben */ { printf("%s", newStd); gotoxy(14,3); /*Editieren des neuen Standes */ ks = dgetch(NOECHO); if(ks == ESC || ks == BS) { /* Abbruch durch ESC oder BkSp */ } else { /* Neuen ZS annehmen */ memset(newStd,0,sizeof(newStd)); gotoxy(14,3); printf(" "); get_kybrd_input(newStd,7,14,3,NUMLOCK); /* Speichern in Datei */ sprintf(file_buffer,"%-10s%-7s%-7s%-2s%-2s%-61s", zNr, oldStd, newStd, ueber, anzSt, einbau); fseek(inv_file, 0, SEEK_END); fwrite(file_buffer,88,1,inv_file); fputs("\n",inv_file); } } else /* Neuer ZS liegt noch nicht vor */ { memset(newStd,0,sizeof(newStd)); /*Eingabe des neuen Standes */ get_kybrd_input(newStd,7,14,3,NUMLOCK); /* Speichern in Datei */ sprintf(file_buffer,"%-10s%-7s%-7s%-2s%-2s%-61s", zNr, oldStd, newStd, ueber, anzSt, einbau); fseek(inv_file, 0, SEEK_END); fwrite(file_buffer,88,1,inv_file); fputs("\n",inv_file); } } else /* Z„hlernummer nicht in Datei vorhanden */ { clrscr(); gotoxy(3,3); printf("nicht gefunden..."); delay(1500); } } } /* end of while(collect_flag) */ fclose(inv_file); /* close the inventory file */ } /* end of collect_data() */ /********************************************************************************* * int lookup(void) NEU * * * * Function: Sucht die richtige Z„hlernummer in der Z„hlerdatei. Wird die * * richtige Nummer gefunden, werden die Daten ausgegeben. * * * * Return Values: 0 = Item not found * * 1 = Item was found * * * *********************************************************************************/ int lookup(void) { int rc = 0; char file_buffer[90]; /* hier wird eine einzelne Zeile gespeichert */ char data_buffer[90]; /* hier wird die Z„hlernummer zum Suchen zwischengespeichert */ char temp_buffer[90]; /* nicht ben”tigt ??? */ char newStd_buffer[6]; _fmemset(file_buffer, 0, sizeof(file_buffer)); /* Alle Zeichen auf 0 setzen */ _fmemset(data_buffer, 0, sizeof(data_buffer)); /* Alle Zeichen auf 0 setzen */ _fmemset(temp_buffer, 0, sizeof(temp_buffer)); /* Alle Zeichen auf 0 setzen */ fseek(inv_file, 0, SEEK_SET); /* Zeiger auf Dateianfang setzen */ while((fgets(file_buffer, sizeof(file_buffer), inv_file) != NULL)) /* eine Zeile aus inv_file lesen, so lang wie der file_buffer ist */ /* dann in file_buffer speichern */ /* != NULL --> so lange kein Fehler auftritt (z.B. EOF...) */ { strncpy(data_buffer, file_buffer, 9); /* 9 Zeichen nach data_buffer kopieren */ trim_spaces(data_buffer); /* Leerzeichen entfernen */ if(strcmp(zNr, data_buffer) == 0) /* Vergleich. Bei == 0 sind die Strings gleich */ { /* Daten kopieren und Nullzeichen anfgen */ strncpy(newStd_buffer, file_buffer + 17, 6); if (strcmp(newStd_buffer, "000000") != 0) { /*Anscheinend wurde schon ein Wert eingegeben */ strncpy(newStd, file_buffer +17, 6); newStd[sizeof(newStd)] = '\0'; trim_spaces(newStd); } strncpy(ueber, file_buffer + 24, 2); ueber[2] = '\0'; trim_spaces(ueber); strncpy(einbau, file_buffer + 28, sizeof(einbau) - 1); einbau[sizeof(einbau)] = '\0'; trim_spaces(einbau); strncpy(anzSt, file_buffer + 26, 1); anzSt[2] = '\0'; strncpy(oldStd, file_buffer + 10, sizeof(oldStd) - 1); oldStd[sizeof(oldStd)] = '\0'; trim_spaces(oldStd); strncpy(zNr, file_buffer, 9); rc = FOUND; break; } else { rc = NOT_FOUND; } } /* end of while */ return rc; } /* end of function */
-
lese alle datensätze in ein array ein (zeilenweise)
ändere die datensätze
schreibe sie alle (!) wieder in datei (quasi datei neu schreiben)
-
Wow bist Du schnell!
Kannst Du mir da CODE-mässig ein bisl unter die Arme greifen? Bin doch noch so'n NOOB...
-
dazu brauchst du dynamische speicherverwaltung.
#define BUFFSIZE 512 char **ppLines = NULL; char buffer[BUFFSIZE]; int nElements=0;
Einlesen:
while (fgets(buffer, BUFFSIZE, fp) != NULL) { nElements++; // speicher für das pointerarray allokieren ppLines = (char**) realloc (ppLines, nElements*sizeof(char*)); // speicher für den string allokieren ppLines[nElements-1] = (char*) malloc ((strlen(buffer)+1)*sizeof(char)); strncpy(ppLines[nElements-1], buffer, strlen(buffer)); }
Dann arbeite mit den Datensätzen und schreibe sie wieder in datei
am ende freigeben nicht vergessen
if (ppLines) { for (int i=0; i<nElements; i++) { if (ppLines[i]) { free (ppLines[i]); ppLines[i] = NULL; } } free (ppLines); ppLines = NULL; }
-
"fp" in fgets ist der Verweis auf meine Datei, richtig??
Sieht ja alles schon ganz gut aus... Kannst Du mir noch zeigen, wie ich dann in den Daten rumschreiben kann und das ganze dann in die Datei zurückschreiben kann??
Ich versteh zwar was Du mir da gepostet hast, aber ich würde nie selber auf sowas kommen...
Danke!!!
-
Doom5000 schrieb:
"fp" in fgets ist der Verweis auf meine Datei, richtig??
Richtig
Doom5000 schrieb:
Ich versteh zwar was Du mir da gepostet hast, aber ich würde nie selber auf sowas kommen...
das glaub ich dir nicht
was machst du den mit deiner funktion fwrite()?
habe mir gerade noch mal deinen post angeschaut, glaubst du nicht es ist besser alles in eine Struktur zu packen?
-
fwrite schreibt mir eine Zeile in die Datei. Aber eben unten dran...
Ich bin jetzt schon soweit, dass er den dynamischen Speicher richtig aufbaut, dann die richtige Zeile raussucht, jetzt muss ich nur noch das mit dem Überschreiben hinkriegen. Insgesamt scheint das aber zu klappen!
Wenns läuft werde ich das hier nochmal posten, vielleicht kann man dann ja noch das ein oder andere "hübsch" machen...
-
wie kann ich denn vor dem schreiben am besten die Datei wieder ganz leer machen?? Ich hab schon die verschiedenen Modes beim fwrite durchprobiert aber ich bekomm immer noch so komisches Zeug vor meinen eigentlichen Werten. Das Überschreiben an sich scheint aber zu funktionieren...
ÏÝ»ÌÛ þ/Ï›œË¾‘ÛŒÿ/Ϝ˾‘Û?yÒÿèþ/ùœ’ÝÓÍïú/Ϥ™ÀÀ’Üüü/Ϟ¸Á‘Ú¿ý/Ï‹œÍ”Ø?yÒÿµû/ùÝ› Òÿµû/ùÝ›œŒÝÓ¯ø/ÏÝ›ÁÄœÚù/Ïœ–Á˘Ûÿý/Ïš‘ƾÛ?yÒÿØþ/ùÝ”’“ÝÓßú/Ïš‘¶Ä’ÛŸü/Ï—£¶»‰ßŸþ/Ï 02 WOO.V \ QB03 Q W ` f lumme ]VR0508002 020000 000000 ‡ áÒN‡ep Tÿ ð€ ðoï ð À £‡oï ðoï ðoï ðoï ðš áÒep \‡Mø ðÍÎI‡9ç ð:ÈéÎ( ì†ì÷P&ÿw&ÿwšÿÿ †ì÷ŒVþ‰Fü‹Fþ‹Vü‰Fú‰Vø3öé¨ ÿvþÿvü¸~ Pšÿÿ ‰Vú‰FøFúué‹ Ä^ø&Æ †Ò÷ QB0306004 001000 5500 0 4 Testblatt Zeile:1 Spalte:1 Nummer:1 (ENDE) VQ0577000 009000 000000 1 4 Testblatt Zeile:1 Spalte:2 Nummer:2 VR0508002 020000 000000 0 5 Testblatt Zeile:1 Spalte:3 Nummer:3 QB0306003 100000 000000 0 6 Testblatt Zeile:2 Spalte:1 Nummer:4 VQ0576000 900000 000000 1 6 Testblatt Zeile:2 Spalte:2 Nummer:5
-
habs schon....
mit "wt+" hats gut geklappt!
-
So, das funktioniert jetzt alles schon ziemlich gut. Problematisch wirds aber, wenn ich meine Original-Zählerdatei teste: Sie hat knapp 1000 Zeilen, womit diese dynamische Speicherverwaltung anscheinend nicht klarkommt... Kann man das irgendwie noch aufbohren, oder muss ich das anders machen?
Die ganze Geschichte funktioniert, aber um die richtige Nummer im Speicher zu finden braucht er gut 2 Minuten... (auf dem Handheld)
Gibts da noch irgendeine andere Möglichkeit das zu realisieren??
Hier nochmal der aktuelle Code:
(nur die collect_data-Funktion)void collect_data(void) { #define BUFFSIZE 90 int ks, rc; /* ks=Keystroke, rc=ReturnCharacter */ int collect_flag = 1; char file_buffer[95]; /* Puffer fr die Daten aus der Datei */ char **ppLines = NULL; char buffer[BUFFSIZE]; int nElements = 0; int i; char zSuch_buffer[10]; //Puffer zum Speichern der gesuchten Z-Nr. while(collect_flag) { memset(zNr,0,sizeof(zNr)); /* Variablen werden mit Nullwerten gefllt */ memset(oldStd,0,sizeof(oldStd)); memset(newStd,0,sizeof(newStd)); memset(ueber,0,sizeof(ueber)); memset(anzSt,0,sizeof(anzSt)); memset(einbau,0,sizeof(einbau)); inv_menu(); // Inventurmen zeigen rc = get_scan_input(zNr,10,7,1,0); // Nummer einlesen if(rc == -1) // ESC wurde gedrckt { collect_flag = 0; break; } trim_spaces(zNr); if(*zNr) { if((inv_file = fopen(INVFILE, "r")) == NULL) { clrscr(); gotoxy(2,1); printf("Dateifehler"); delay(1000); } if(lookup()) /* Nummer in der Datei suchen Variablen setzen */ { // Z-Nummer gefunden, Daten ausgeben: gotoxy(14,2); printf("%s",oldStd); gotoxy(10,4); printf("%s", anzSt); if(strcmp(ueber,"1") == 0) //šberlauf anzeigen { gotoxy(13,4); printf("šberlauf"); } gotoxy(1,6); printf("%s",einbau); gotoxy(14,3); shift_lock(1); //Aufbau des dynamischen Speichers fseek(inv_file, 0, SEEK_SET); nElements = 0; while(fgets(buffer, BUFFSIZE, inv_file) != NULL) { nElements++; //Speicher fr Pointerarray allokieren ppLines = (char**) realloc (ppLines, nElements*sizeof(char*)); //Speicher fr den String allokieren ppLines[nElements-1] = (char*) malloc ((strlen(buffer)+1)*sizeof(char)); strncpy(ppLines[nElements-1], buffer, strlen(buffer)); } if(strcmp(newStd, "000000") != 0) // Neuer ZS wurde schon eingegeben: { gotoxy(14,3); printf("%s", newStd); gotoxy(14,3); // evtl. Editieren des neuen Standes: ks = dgetch(NOECHO); if(ks == ESC || ks == BS) { // Abbruch durch ESC oder BkSp } else { // Neuen ZS annehmen: memset(newStd,0,sizeof(newStd)); gotoxy(14,3); printf(" "); get_kybrd_input(newStd,7,14,3,NUMLOCK); for(i=0; i<nElements;i++) { //Z„hlernummer zum Suchen kopieren strncpy(zSuch_buffer, ppLines[i], 9); //9 Zeichen der Zeile in den Buffer zSuch_buffer[9] = '\0'; if(strcmp(zNr, zSuch_buffer) == 0) { //Zeile im Speicher erneuern sprintf(ppLines[i],"%-10s%-7s%-7s%-2s%-2s%-61s", zNr, oldStd, newStd, ueber, anzSt, einbau); } } } }//Ende von If "ZS lag schon vor" else // Neuer ZS liegt noch nicht vor: { memset(newStd,0,sizeof(newStd)); // Eingabe des neuen Standes get_kybrd_input(newStd,7,14,3,NUMLOCK); //richtige Zeile suchen for(i=0; i<nElements;i++) { //Z„hlernummer zum Suchen kopieren strncpy(zSuch_buffer, ppLines[i], 9); //9 Zeichen der Zeile in den Buffer zSuch_buffer[9] = '\0'; if(strcmp(zNr, zSuch_buffer) == 0) { //Zeile im Speicher erneuern sprintf(ppLines[i],"%-10s%-7s%-7s%-2s%-2s%-61s", zNr, oldStd, newStd, ueber, anzSt, einbau); } } }//Ende von Else "ZS lag noch nicht vor" //Datei erstmal wieder zu machen fclose(inv_file); //Datei mit anderem Mode wieder aufmachen if((inv_file = fopen(INVFILE, "wt+")) == NULL) { clrscr(); gotoxy(2,1); printf("Dateifehler"); delay(1000); } // Zurckschreiben in Datei: for(i=0; i<nElements; i++) { fwrite(ppLines[i],88,1,inv_file); fputs("\n",inv_file); } //OutFile dicht machen fclose(inv_file); //dynamischen Speicher wieder freigeben if(ppLines) { for(i=0; i<nElements; i++) { if(ppLines[i]) { free(ppLines[i]); ppLines[i] = NULL; } } free(ppLines); ppLines = NULL; } }//Ende von If "Z-Nummer gefunden" else // Z„hlernummer nicht in Datei vorhanden { clrscr(); gotoxy(3,3); printf("nicht gefunden..."); delay(1500); } }//Ende von if(*zNr) }// Ende von while(collect_flag) }//Ende von collect_data()
-
MOIN!
so, bin jetzt schon mal ne ganze Ecke weiter: Ich lasse den dyn. Speicher jetzt einfach am Anfang der Routine einmal erzeugen, dann wird damit gearbeitet beim Verlassen der Funktion wird dann alles zurück in die Datei geschrieben.
Dieses Zurückschreiben dauert allerdings SEHR lange auf meinen Handhelds... (Ca. 4 min)
Kann man das irgendwie noch schneller lösen?? Das Einlesen der Datei dauert auch nur ein paar Sekunden...So wirds bei mir zurückgeschrieben:
if((inv_file = fopen(INVFILE, "wt+")) == NULL) { clrscr(); gotoxy(2,1); printf("Dateifehler"); delay(1000); } // dyn. Speicher zurückschreiben in Datei: for(j=0; j<nElements; j++) { fwrite(ppLines[j],88,1,inv_file); fputs("\n",inv_file); clrscr(); gotoxy(1,1); printf("Datei wird geschrieben\n"); printf("Zähler-Nr.: %d", j); } //File dicht machen fclose(inv_file);
-
gibst du den speicher auch wieder frei?
-
Ja, der Speicher wird beim Beenden des Programmes wieder freigegeben. Dies erfolgt erst so spät, weil ich für andere Bereiche der Anwendung die Daten auch noch brauche. Funktioniert bis jetzt auch alles prima. Im Prinzip kann man damit jetzt schon ganz gut arbeiten. Das Rückschreiben in die Datei ist zwar etwas nervig, aber man kann sich darauf einstellen.
Falls jemand noch Verbesserungsvorschläge hat, gerne her damit...
Chris
Dies erfolgt am Ende der Main-Methode:
// dynamischen Speicher wieder freigeben if(ppLines) { for(j=0; j<nElements; j++) { if(ppLines[j]) { free(ppLines[j]); ppLines[j] = NULL; } } free(ppLines); ppLines = NULL; }