Problem mit sehr großen Dateien (>2Gb)



  • Hi,
    ich habe ein Programm geschrieben, das eine Statistik über das Vorkommen der verschiedenen Bytes, innerhalb einer Datei erstellt.

    Bei kleinen Dateien funktioniert das auch soweit, sobald ich mich allerdings an größere rantraue gibt es einen Fehler bei der Dateigrößenbestimmung mit fseek.

    Die Filegröße benötige ich prinzipiell nur um damit den Puffer beim letzten Durchgang zu begrenzen.
    Ich wäre sehr daakbar wenn mir Jemand sagen könnte wie ich
    a. die Filegröße trotzdem herausbekomme
    b. den Puffer ohne die Filegröße, anpassen kann

    Hier mal die benutzten Funktionen:

    int initBlock(char *fname)
    {
    	BOOLEAN EXIT;
    	file = fopen(fname,"rb");
    
    	if(file != NULL)
    	{
    		fseek(file,0L,SEEK_END);
    		fsz=ftell(file);
    		rewind(file);
    		runs = (int)fsz/BUFSZ;
    		runs++;
    		printf("FileSize:%d Byte, %d Runs\n",fsz,runs);
    		EXIT = true;
    	}else
    	{
    		EXIT = false;
    	}
    	return EXIT;
    
    int loadNxtBlock(char *buffer, FILE *file)
    {
    	if(runs>1)
    	{
    		fread(buffer,sizeof(char),BUFSZ,file);
    	}else
    	{
    		fread(buffer,sizeof(char),fsz%BUFSZ,file);
    	}
    	runs--;
    	return EXIT_SUCCESS;
    }
    }
    


  • Diese Grenze hört sich sehr nach FAT16 an. Hatte das Problem mit einer SD-Karte, die eben diese Größe nicht überschreiben kann. Schau mal, ob es eine ähnliche Beschränkung für die f-Befehle auch gibt.



  • Hallo,

    blubb schrieb:

    a. die Filegröße trotzdem herausbekomme

    indem du Betriebssystemfunktionen benutzt. Für Microsoft z.B. gibts dafür spezielle WinApi Funktionen.

    blubb schrieb:

    b. den Puffer ohne die Filegröße, anpassen kann

    indem du die Datenblöcke einfach an eine verkettete Liste anhängst.

    Gruß,
    B.B.



  • Heimelchen schrieb:

    Diese Grenze hört sich sehr nach FAT16 an. Hatte das Problem mit einer SD-Karte, die eben diese Größe nicht überschreiben kann. Schau mal, ob es eine ähnliche Beschränkung für die f-Befehle auch gibt.

    liegt nicht an fat16
    eher an der tatsache dass ftell ein long zurückgibt - auf 32 bit systemen wohl auch 32 bit lang (signed) -> 2147483648 sieht irgendwie nach 2 gb aus.

    unter windows wohl eher sowas wie: http://msdn.microsoft.com/en-us/library/Aa364955
    unter linux gibts afaik fseeko und ftello.



  • Big Brother schrieb:

    Hallo,

    blubb schrieb:

    a. die Filegröße trotzdem herausbekomme

    indem du Betriebssystemfunktionen benutzt. Für Microsoft z.B. gibts dafür spezielle WinApi Funktionen.

    blubb schrieb:

    b. den Puffer ohne die Filegröße, anpassen kann

    indem du die Datenblöcke einfach an eine verkettete Liste anhängst.

    Gruß,
    B.B.

    Das Programm sollte nicht betriebssystemspezifisch sein daher hilft mir das leider nicht weiter.

    Wie soll mir den eine verkettete Liste helfen? Das einlesen ist ja nicht das Problem nur das die Datei eben (im Normalfall) kein Vielfaches der Puffergröße ist, und somit im letzten Durchgang, teilweise Datenmüll im Puffer steht.



  • Es geht auch BS-unabhängig, z.B.

    #define BLOCKSIZE 65536
    
    void verarbeiteBlock(const unsigned char *block,unsigned blocksize)
    {
    }
    unsigned naechsterBlock(FILE *f,unsigned char *puffer)
    {
      unsigned x=0;
      fpos_t fp;
      if( fgetpos(f,&fp), fread(puffer,BLOCKSIZE,1,f)==1 )
        return BLOCKSIZE;
      fsetpos(f,&fp);
      while( fread(puffer+x,1,1,f)==1 )
        ++x;
      return x;
    }
    main(){
      FILE *datei=fopen("bla","rb");
      unsigned bs;
      unsigned char puffer[BLOCKSIZE];
      while( bs=naechsterBlock(datei,puffer) )
        verarbeiteBlock(puffer,bs);
      fclose(datei);
    }
    


  • blubb schrieb:

    ...
    Die Filegröße benötige ich prinzipiell nur um damit den Puffer beim letzten Durchgang zu begrenzen.
    ...
    ... und somit im letzten Durchgang, teilweise Datenmüll im Puffer steht.

    Brauchst nix begrenzen, wird kein Müll drin stehen, wenn der Puffer vor jedem Einlesen sauber mit memset genullt ist.
    Bei EOF zählst du den 'Rest' im Puffer einfach dazu. Die restliche Anzahl Bytes bekommst du mit strlen für Textdateien, bzw. über den Rückgabewert von fread bei Binärdateien mit möglichen Nullbytes.



  • Ach ja stimmt vielen dank 🙂



  • Warum verwendest du nicht einfach den Rückgabewert von fread ? Der sagt dir, wie viele chars erfolgreich gelesen wurden. Beim letzten Block wird es dann i.A. nicht mehr die volle Anzahl an Bytes sein.



  • ProgChild schrieb:

    Warum verwendest du nicht einfach den Rückgabewert von fread ? Der sagt dir, wie viele chars erfolgreich gelesen wurden. Beim letzten Block wird es dann i.A. nicht mehr die volle Anzahl an Bytes sein.

    Genau dies macht bereits das o.g. Beispiel.



  • Wutz schrieb:

    Genau dies macht bereits das o.g. Beispiel.

    Ja, in der Tat, aber ziemlich umständlich.

    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    

    Wenn du einfach die Verwendung von size und nmemb in deinem Beispiel vertauscht, also

    len = fread(buf, 1, BUFFER_SIZE, fp);
    

    liefert dir fread, schon die Anzahl der gelesenen Bytes. Da kannst du dir die Schleife sparen.


Log in to reply