fseek() - Verständnisproblem



  • Hallo!

    ich verstehe die funktion fseek nicht wirklich.

    int fseek (FILE * stream, long offset, int whence);
    
    Beschreibung:
    Die Funktion fseek() setzt den Dateipositions-Zeiger der durch stream definierten
    Datei auf die Position, die offset Bytes von whence entfernt ist.
    

    Diesen Satz in der Beschreibung verstehe ich nicht. Die Funktion settzt den Cursor auf die Position die offset Bytes von whence entfernt ist.

    Heißt das jetzt wenn ich schreibe z.B. fseek(file,0,SEEK_END), dann befindet sich der Curser am Ende oder? Da der Cursor auf die Position gesetzt wird, die offset Bytes(in dem Fall 0) vom Ende der Datei entfernt ist, kann der Cursor nur am Ende der Datei sein.

    Was sind "offset Bytes"?

    Und ftell fängt einfach von vorne und zählt die Bytes bis zum Cursor?

    mfg sparrow



  • Offset bedeutet einfach Abstand. "offset Bytes" soll andeuten, dass der Abstand in Bytes gemessen wird.



  • Hier gibt es ein Beispiel zu ab Position 9:
    http://www.cplusplus.com/reference/clibrary/cstdio/fseek/

    MfG f.-th.



  • Ok, danke dann testen wir das gleich in eine Aufgabe^^.

    Ich habe mehrere Termine in einem Binärfile gegeben. Ein Termin ist in die Struktur, die Datum_von, Datum_bis, Beschreibung, Teilnehmer etc. beinhaltet.

    Und ich soll nun einen bestimmten Termin irgendwo zwischenfügen, z.B. diesen Termin zwischen 1. und 2. Termin im Binärfile einfügen.

    Meine Idee war/ist mit fseek die Position herausfinden, das müsste klappen.

    Aber danach wie man den Termin in das File einfügt weis ich nicht genau, dabei gehn sicher ein paar Termine verloren, weil wenn ich das file zum Schreiben öffne dann erstellt es ein neues und es steht nur der eine Termin drinnen der zwischen 1. und 2. Termin eingeschoben werden soll.
    Und wenn ich das File im appendmode öffne dann wird der bestimmte Termin am Ende hinzugefügt richtig?

    Gebt mir bitte paar Tipps wie ich das machenk könnte.

    Hier der Ausschnitt:

    termin* termin_einfügen(char filename[])
    {
      FILE* inFile=NULL;
    
    	termin* all_termin=NULL;
    	termin termine;
    
    	int len=0;
    	int termin_zahl=0;
    	int byte_anz=0;
    
    //hier einfach irgendeinen Termin festlegen der eingefügt werden soll
    
    	sprintf(termine.thema  ,"programmieren");
      strcpy(termine.beschreibung  ,"fseek ueben");
      strcpy(termine.teilnehmer  ,"ich");
    	termine.von.jahr = 2012;
      termine.von.mon = 2;
    	termine.von.tag = 24;
    
      termine.status = OFFEN;
    	termine.priority = 1;
    
    	inFile=fopen(filename,"w+b");
    	if(inFile == NULL)
    	{
    	  printf("Die datei %s konnte nicht geöffnet werden",filename);
    		exit(-1);
    	}
    
    	fseek(inFile,0L,SEEK_END);
    	len=ftell(inFile)/sizeof(termin);
    
      all_termin=(termin *)malloc(sizeof(termin)*len);
    	if(all_termin != NULL)
    	{
    		printf("Geben Sie die Zahl des Termins ein, wo dann Ihr neuer Termin eingefügt werden soll:");// wenn man hier z.b. 3 eingibt dann wird der bestimmte Termin nach dem 3. Termin im binärfile eingefügt
    		scanf("%d",&termin_zahl);
    
    		byte_anz=sizeof(termin)*termin_zahl;
    
    		fseek(inFile,byte_anz,SEEK_SET);
    
    		fwrite(&termine,sizeof(termin),1,inFile);
    	}
    
    	else
    	{
    	  printf("Memory allocation failure!");
    	}
    
    	return(all_termin);
    }
    


  • Du liest Datei1 (Termine) und schreibst das Gelesene in Datei2, bis Du den Punkt erreichst, wo eingefügt werden soll. Hier schreibst Du den einzufügenden Satz in Datei2 und liest anschließend wieder Datei1 bis Ende und schreibst alles in Datei2.
    So fügst Du quasi den Satz in Datei2 ein, verschiebst Datei2 auf Datei1 und keiner hat's gemerkt.



  • Danke!

    Deine Lösung ginge ja ganz ohne fseek oder?

    Man öffnet Datei1 im rb-mode liest halt die ersten 3 Termine mit fread aus(wenn man nach dem 3. einfügen will). Diese 3 Termine schreibt man dann in Datei2 und hängt mittels appendreadmode den einzufügenden Termin dazu. Man lest Datei1 fertig aus und hängt es nach dem eingefügten Termin hinzu und dann lest mal die ganzen Termine aus und speichert diese in Datei1 wieder.

    Wie geht das dann genau mit fseek?



  • sparrow12 schrieb:

    Was sind "offset Bytes"?

    offset ist der Name des zweiten Parameters der Funktion. Falls dich die Formulierung verwirrt ersetze offset durch x. Dann würde dort stehen "x Bytes".



  • Zu deinem Problem: lese alle Einträge in dein Programm ein. Manipuliere im Speicher deine Einträge und schreibe diese anschließend in die Datei.

    Ansonsten solltest du die Programmlogik und Datenhaltung voneinander trennen. Verwende doch eine Datenbank-Bibliothek, wie die "Berkeley DB" oder SQLite. Oder nutze das Dateisystem und schreibe eine Datei pro Eintrag. Alle Einträge findest du dann durch Iteration des Verzeichnisinhalts.



  • f.-th. hatte oben einen Link mit einem Beispiel gepostet.

    Allerdings wird der Modus "a" immer dafür sorgen, dass Inhalt am Ende angehängt wird. Wenn Du in der selben Datei, an der Du anhängen möchtest den Filepointer positionieren willst, musst Du "a+" verwenden. Dennoch wird nicht an der Position des File-Pointers, sondern am Ende der Datei angefügt, wenn Du schreibst.

    Ich kenne im Grunde nur diese Möglichkeit, die bereits beschrieben wurde: die Datei1 auslesen und Datei2 beschreiben, bis die passende Position erreicht ist, dann den Satz einfügen und wiederum Datei1 auslesen und Datei2 beschreiben, bis Datei1 am Ende ist.



  • Danke euch!

    B3rnDi, deine Version verstehe ich ok.

    Sorry, Ein C-Progger, aber von solchen Datenbanken hab ich noch nie gehört und ich habe keine blassen Schimmer davon, da wir sowas noch nicht lernten.

    Aber kennt den niemand eine lösung mit fseek? In meinem Programm oben habe ich ja fseek verwendet und es setzt den Cursor genau dorthin wo der Termin eingeschoben werden soll, aber wie es weiter geht weis ich halt nicht.



  • Lies dir noch mal die Bedeutung von den verschidenen Modi von fopen durch: http://www.cplusplus.com/reference/clibrary/cstdio/fopen/
    Du hast die falschen benutzt.

    Einfügen kannst du aber nicht mit fseek, nur überschreiben.



  • Danke habe ich gar net so beachtet 🙂

    Ich habs jetzt programmiert theoretisch müsste es so funktionieren glaube ich aber es kommt ein fatal error. Fatal error treten doch auch auf wenn man ein Unterprogramm aufruft, aber es keins gibt oder so... Ist aber nicht so in meinem Fall.

    1>LINK : fatal error LNK1168: "Debug\termin_original.exe" kann nicht zum Schreiben geöffnet werden.

    Hier mal das Unterprogramm vielleicht könnt ihr herausfinden wo der error liegt, ansonsten sagt es wenn ich das ganze Programm posten soll:

    termin* termin_einfügen(char filename[])
    {
      FILE* inFile=NULL;
    
    	termin* all_termin=NULL;
    	termin termine;
    	termin* temp = NULL;
    	int len=0;
    	int termin_zahl=0;
    	int byte_anz=0;
    	int hilf=0;
    
    	sprintf(termine.thema  ,"unser eingeschobener termin");
      strcpy(termine.beschreibung  ,"gibts keine");
      strcpy(termine.teilnehmer  ,"ich bin alleine");
    	termine.von.jahr = 2012;
      termine.von.mon = 2;
    	termine.von.tag = 28;
    
      termine.status = OFFEN;
    	termine.priority = 1;
    
    	inFile=fopen(filename,"r+b");
    	if(inFile == NULL)
    	{
    	  printf("Die datei %s konnte nicht geöffnet werden",filename);
    		exit(-1);
    	}
    
    	fseek(inFile,0L,SEEK_END);
    	len=ftell(inFile)/sizeof(termin);
    
      temp=(termin *)malloc(sizeof(termin)*len);
    	if(temp != NULL)
    	{
    		printf("Geben Sie die Zahl des Termins ein, wo dann Ihr neuer Termin eingefügt werden soll:");
    		scanf("%d",&termin_zahl);
    
    		hilf=len-termin_zahl;
    
    		byte_anz=sizeof(termin)*termin_zahl;
    
    		fseek(inFile,byte_anz,SEEK_SET);
        fread(temp,sizeof(termin),hilf,inFile);
    		fwrite(&termine,sizeof(termin),1,inFile);
    		fseek(inFile,sizeof(termin),SEEK_CUR);
    		fwrite(temp,sizeof(termin),hilf,inFile);
    	}
    	else
    	{
    	  printf("Memory allocation failure!");
    	}
    
    	return(temp);
    }
    


  • Das ist kein Fehler von deinem Programm sondern vom Linker.
    Die Datei "Debug\termin_original.exe" ist gerade schreibgeschützt.
    Das kommt davon, dass noch eine Instanz von deinem Programm läuft (ein Fenster mit deinem Programm ist noch offen).



  • Ok, danke jetzt hab ichs.

    Die nächste Aufgabe ist einen bestimmten Termin suchen im Binärfile und dann auslesen.
    Meine Idee: Ich geben vorher das Datum ein und dann vergleiche ich das Datum mit den Datums im Binärfile wenn die gleich sind speichere ich sie in eine Adresse wo ein Pointer draufzeigt, da es ja mehrere Termine an einem Tag geben kann. Problem ist nur das ich 2mal fast den selben Vorgang mache und das ist nicht gut.

    Hier mal der Ausschnitt:

    termin* termin_einfügen(char filename[])
    {
      FILE* inFile=NULL;
    
    	termin* all_termin=NULL;
    	termin termine;
    	termin* temp = NULL;
    	int len=0;
    	int termin_zahl=0;
    	int byte_anz=0;
    	int hilf=0;
    	int strukt=0;
    
    	sprintf(termine.thema  ,"unser eingeschobener termin");
      strcpy(termine.beschreibung  ,"gibts keine");
      strcpy(termine.teilnehmer  ,"ich bin alleine");
    	termine.von.jahr = 2012;
      termine.von.mon = 2;
    	termine.von.tag = 28;
    
      termine.status = OFFEN;
    	termine.priority = 1;
    
    	inFile=fopen(filename,"r+b");
    	if(inFile == NULL)
    	{
    	  printf("Die datei %s konnte nicht geöffnet werden",filename);
    		exit(-1);
    	}
    
    	fseek(inFile,0L,SEEK_END);
    	len=ftell(inFile)/sizeof(termin);
    
      temp=(termin *)malloc(sizeof(termin)*len);
    	if(temp != NULL)
    	{
    		printf("Geben Sie die Zahl des Termins ein, wo dann Ihr neuer Termin eingefügt werden soll:");
    		scanf("%d",&termin_zahl);
    
    		hilf=len-termin_zahl;
    		strukt=sizeof(termin);
    
    		byte_anz=sizeof(termin)*termin_zahl;
    
    		fseek(inFile,byte_anz,SEEK_SET);
        fread(temp,sizeof(termin),hilf,inFile);
    		rewind(inFile);
    		fseek(inFile,byte_anz,SEEK_SET);
    		fwrite(&termine,sizeof(termin),1,inFile);
    		fwrite(temp,sizeof(termin),hilf,inFile);
    	}
    	else
    	{
    	  printf("Memory allocation failure!");
    	}
    
    	return(temp);
    }
    

    Hier die lange Struktur:

    struct timestamp_struct
    {
    	short jahr;
    	short mon;
    	short tag;
    	int   min; 
    };
    
    typedef struct timestamp_struct timestamp; 
    
    struct termin_struct 
    {
      char thema[MAX_THEMALEN];
    	timestamp von;
    	timestamp bis;
    	char teilnehmer[MAX_TEILNEHMER];
      short priority;
    	char beschreibung[MAX_BESCHR];
      short status;
    };
    
    typedef struct termin_struct termin;
    

    Natürlich könnte ich die gesuchten Termine auch gleich im Unterprogramm ausgeben, aber zum Ausgeben habe ich eine weitere Funktion, die ich dann im Hauptprogramm aufrufen werde.

    Diese sieht so aus:

    void termin_out(termin  termin_zur_ausgabe)
    {
    	printf("------------------\n");
    	printf("Termin: %s \nTeilnehmer %s \nprio %d \nBeschreibung: %s \nStatus %d\n",termin_zur_ausgabe.thema,termin_zur_ausgabe.teilnehmer,termin_zur_ausgabe.priority,termin_zur_ausgabe.beschreibung,termin_zur_ausgabe.status);
    	printf("------------------\n");
    }
    

    Naja wie könnte ich das nun Verbessern?



  • Oh sorry, das ist der falsche Ausschnitt.

    Den meine ich:

    termin* termin_search(char filename[])
    {
      FILE* outFile=NULL;
    	termin temp;
    	timestamp dat_von;
    	termin* term_gesucht=NULL;
    	int anz=0;
    
    	outFile=fopen(filename,"r+b");
    	if(outFile == NULL)
    	{
    	  printf("File %s could not be opened!",filename);
    		exit(-1);
    	}
    
    	printf("Geben Sie das Datum des/der gesuchten Termin(e) ein(TTMMJJ):");
    	scanf("%d",dat_von.tag);
    	scanf("%d",dat_von.mon);
    	scanf("%d",dat_von.jahr);
    
      while(!feof(outFile))
    	{
    	  fread(&temp,sizeof(termin),1,outFile);
    
    		if(temp.von.tag == dat_von.tag && temp.von.mon == dat_von.mon && temp.von.jahr == dat_von.jahr)
    		{
    		  anz++;
    		}
    	}
    
    	rewind(outFile);
    
      term_gesucht=malloc(sizeof(termin)*anz);
    
    	while(!feof(outFile))
    	{
    	  fread(&temp,sizeof(termin),1,outFile);
    
    		if(temp.von.tag == dat_von.tag && temp.von.mon == dat_von.mon && temp.von.jahr == dat_von.jahr)
    		{
    		  term_gesucht=temp;
    			term_gesucht++;
    		}
    	}
    
    	return(term_gesucht);
    }
    


  • Statt

    sparrow12 schrieb:

    while(!feof(outFile))
    	{
    	  fread(&temp,sizeof(termin),1,outFile);
    

    ist viel einfacher und sicherer

    while( 1==fread(&temp,sizeof(termin),1,outFile) )
    	{
    	  ;
    

    da hierbei nur vollständig gelesene Strukturblöcke berücksichtigt werden.



  • Danke!

    Ich habs jetzt geschafft das ich nur eine Schleife brauche, glaube ich :).
    Siehe comments pls.

    void termin_search(char filename[])
    {
      FILE* outFile=NULL;
    	termin temp;
    	timestamp dat_von = {0,0,0,0};
    
    	outFile=fopen(filename,"rb");
    	if(outFile == NULL)
    	{
    	  printf("File %s could not be opened!",filename);
    		exit(-1);
    	}
    
    	printf("Geben Sie das Datum des/der gesuchten Termin(e) ein(TTMMJJ):");
    	scanf("%d",&dat_von.tag);//wenn ich hier z.B. 26 eingebe
    	scanf("%d",&dat_von.mon);//und dann hier 2, dann steht in dat_von.tag plötzlich 0
    	scanf("%d",&dat_von.jahr);//wenn ich hier 2012 eingebe, dann steht in dat_von.mon auch 0, aber jahr 2012 bleibt erhalten
    
    	while(1 == fread(&temp,sizeof(termin),1,outFile))
    	{
    	  if(temp.von.tag == dat_von.tag && temp.von.mon == dat_von.mon && temp.von.jahr == dat_von.jahr)
    		{
    		  termin_out(temp);
    		}
    	}
    }
    

    Warum ist das so? Ich finde keine Fehler 😞 .



  • sparrow12 schrieb:

    scanf("%d",&dat_von.tag);//wenn ich hier z.B. 26 eingebe
    	scanf("%d",&dat_von.mon);//und dann hier 2, dann steht in dat_von.tag plötzlich 0
    	scanf("%d",&dat_von.jahr);//wenn ich hier 2012 eingebe, dann steht in dat_von.mon auch 0, aber jahr 2012 bleibt erhalten
    

    Warum ist das so? Ich finde keine Fehler 😞 .

    Das liegt daran, dass du dein Programm hier falsch entworfen hast, du verlangst von Nutzer EINE Eingabe ("TTMMJJ"), im Code verwendest du aber 3 Eingabefunktionen (die jeweils eine Eingabe erwarten), also besser (und viel einfacher):

    if( 3==scanf("%02d%02d%02d",&tag,&monat,&jahr) )
    {
    }
    while( '\n'!=getchar() );
    


  • Wenn du dir mal deine timestamp_struct ansiehst

    struct timestamp_struct
    {
        short jahr;
        short mon;
        short tag;
        int   min;
    };
    

    kannst du erkennen, dass jahr, monat und tag vom typ short sind.

    %d ist bei scanf aber für ein int da.

    Also nochmal die Doku für scanf durchlesen, wie man ein short einliest.
    Dafür gibt es keinen eigenen Typ sondern einen Modifier.
    Das ergibt dann %hd


Anmelden zum Antworten