ifstream liest falschen wert ein



  • das sind alle funktionen, die auf den stream zugreifen

    void Test::skip(int numberOfBytes)
    {
    	std::cout << "skip:\t\t" << numberOfBytes << "\n"; 
    	stream.ignore(numberOfBytes); 
    }
    
    int Test::readByte()
    {
    	char byte; 
    	stream.read(&byte, 1);
    
    	std::cout << "byte:\t\t" << (int)byte << "\n"; 
    
    	return (int)byte;
    }
    
    unsigned char Test::readUnsignedByte()
    {
    	unsigned char byte;
    	stream.read(((char*)&byte), 1);
    
    	std::cout << "ubyte:\t\t" << (int)byte << std::endl;
    
    	return byte; 
    }
    
    int Test::readInt()
    {
    	unsigned char bytes[4];
    	stream.read((char*)bytes, 4); 
    
    	int i = ((bytes[3] & 0xFF) << 24) | ((bytes[2] & 0xFF) << 16) | ((bytes[1] & 0xFF) << 8) | (bytes[0] & 0xFF); 
    
    	std::cout << "int:\t\t" << i << "\n"; 
    	std::cout << "\t\t\t" << (int)bytes[3] << " " << (int)bytes[2] << " " << (int)bytes[1] << " " << (int)bytes[0] << "\n"; 
    
    	return i; 
    }
    
    long long Test::readLong()
    {
    	unsigned char bytes[8];
    	stream.read((char*)bytes, 8); 
    
    	long long l = ((long long)(bytes[7] & 0xFF) << 56) | ((long long)(bytes[6] & 0xFF) << 48) | ((long long)(bytes[5] & 0xFF) << 40) | ((long long)(bytes[4] & 0xFF) << 32) | 
    		   ((long long)(bytes[3] & 0xFF) << 24) | ((long long)(bytes[2] & 0xFF) << 16) | ((long long)(bytes[1] & 0xFF) << 8) | (bytes[0] & 0xFF); 
    
    	std::cout << "long:\t\t" << l << "\n"; 
    
    	return l; 
    }
    
    string Test::readString(int size, int len)
    {
    	int length = (size > 0 ? size : len);
    	char* bytes = new char[length];
    
    	stream.read(bytes, length); 
    
    	return newString(bytes, (len >= 0 ? len : size));  
    }
    
    string Test::newString(char *bytes, int length)
    {
    	std::string str; 
    
    	for(int i = 0; i < length; i++)
    		str += bytes[i]; 
    
    	std::cout << "string: length: " << length << " bytes: " << str.c_str() << "\n"; 
    
    	delete[] bytes; 
    	return str; 
    }
    

    Edit:
    das Problem tritt übrigens immer an der selben Stelle auf



  • Holla...
    das sieht mehr nach Java als nach C++ aus...

    - bietet die Klasse stream keine skip() Methode an? Dafür dynamisch Speicher zu reservieren, Daten einzulesen und sofort wieder wegzuwerfen ist, äh, suboptimal. Was passiert, wenn du die ersten 3GB einer Datei überspringen möchtest?
    - die vielen dynamischen Speicheranforderungen lassen sich komplett wegoptimieren (du vergisst auch an mindestens einer Stelle den Speicher wieder freizugeben -> resource leak).
    - du verwendest sowohl c-style casts als auch C++ casts. Bleib´ konsequent bei C++ casts
    - readByte und readUnsignedByte machen das Gleiche, du brauchst eigentlich keine zwei Funktionen dafür (ebenso short, int, long). char und unsigned char sind immer gleich groß und haben nur unterschiedliche Wertebereiche.
    - du verwendest statische Arrays der Länge 1. Warum keine Variable des Datentyps?
    - beim Einlesen eines Strings erzeugst du ein temporäres Array, liest die Stringdaten hinein und kopierst die Zeichen Zeichen-für-Zeichen. Das sind gleich mehrere Performance Leaks in einer Funktion. Du kannst im String Objekt selbst die Puffergröße reservieren und direkt in den Puffer lesen.
    - mit templates lassen sich hervorragend alle integralen Datentypen (inkl. Endianess Korrektur) umsetzen, du brauchst lediglich eine Funktion zum Lesen von char/short/int/long/long long

    C++ und Java haben unterschiedliche Paradigmen, du wendest hier Java Paradigmen unter C++ an, was im besten Fall ineffizienten Code produziert.



  • - bietet die Klasse stream keine skip() Methode an? Dafür dynamisch Speicher zu reservieren, Daten einzulesen und sofort wieder wegzuwerfen ist, äh, suboptimal. Was passiert, wenn du die ersten 3GB einer Datei überspringen möchtest?

    ifstream bietet keine skip-Methode an, zumindest habe ich keine gefunden. Die Dateien, die ich einlese sind aber recht klein (um die 100kb) und ich überspringe nur wenige Bytes. Der größte Wert liegt glaube ich bei 42 Bytes.

    - die vielen dynamischen Speicheranforderungen lassen sich komplett wegoptimieren (du vergisst auch an mindestens einer Stelle den Speicher wieder freizugeben -> resource leak).

    In der Methode newString habe ich ein 'delete[] bytes' eingefügt. Abgesehen davon habe ich nichts mehr gefunden.

    - du verwendest sowohl c-style casts als auch C++ casts. Bleib´ konsequent bei C++ casts

    die reinterprets habe ich ersetzt

    - du verwendest statische Arrays der Länge 1. Warum keine Variable des Datentyps?

    Habe ich ersetzt:

    char byte;
    stream.read(&byte, 1);

    - beim Einlesen eines Strings erzeugst du ein temporäres Array, liest die Stringdaten hinein und kopierst die Zeichen Zeichen-für-Zeichen. Das sind gleich mehrere Performance Leaks in einer Funktion. Du kannst im String Objekt selbst die Puffergröße reservieren und direkt in den Puffer lesen.

    Ich weiß 😞 , das war schnellste Methode die mir eingefallen ist und die sicher funktioniert. Da werde ich, wenn ich Zeit habe, nach einer besseren Variante suchen.

    - mit templates lassen sich hervorragend alle integralen Datentypen (inkl. Endianess Korrektur) umsetzen, du brauchst lediglich eine Funktion zum Lesen von char/short/int/long/long long

    Mit Templates habe ich mich nur kurz beschäftigt. Mein StreamReader ist auch, zumindest was die Logik betrifft, fertig programmiert, so dass der Aufwand zu groß ist das nochmal umzuschreiben. Im Prinzip geht es "nur" noch um das oben beschriebene Problem.

    Auf jeden Fall danke für die Anregungen!



  • Ab dem Zeitpunkt, wo ich nur noch 11001100 erhalte liefert stream.fail() true zurück. Aber was kann ich dagegen tun?



  • Der Code sieht für C++ grottenschlecht und viel zu umständlich aus!

    Ich kenne mich in Java nicht aus, nur C und C++. Du willst doch nur Folgen von Bytes einlesen. Das Byte-Gefrickel erscheint mir reichlich kompliziert.

    Teile einfach mal mit, was genau in der Datei ankommt.



  • hanzpetr schrieb:

    - bietet die Klasse stream keine skip() Methode an? Dafür dynamisch Speicher zu reservieren, Daten einzulesen und sofort wieder wegzuwerfen ist, äh, suboptimal. Was passiert, wenn du die ersten 3GB einer Datei überspringen möchtest?

    ifstream bietet keine skip-Methode an, zumindest habe ich keine gefunden.

    [url=http://www.cplusplus.com/reference/iostream/istream/seekg/]http://www.cplusplus.com/reference/iostream/istream/seekg/
    [/url]

    hanzpetr schrieb:

    - beim Einlesen eines Strings erzeugst du ein temporäres Array, liest die Stringdaten hinein und kopierst die Zeichen Zeichen-für-Zeichen. Das sind gleich mehrere Performance Leaks in einer Funktion. Du kannst im String Objekt selbst die Puffergröße reservieren und direkt in den Puffer lesen.

    Ich weiß 😞 , das war schnellste Methode die mir eingefallen ist und die sicher funktioniert. Da werde ich, wenn ich Zeit habe, nach einer besseren Variante suchen.

    Da kann man sich was mit std::getline basteln oder etwas in der Art:

    std::vector<char> v(size);
    stream.read(v, size);
    return std::string(v.begin(), v.end());
    

    Wenn du mutig bist, liest du auch gleich in den internen Puffer des Strings ( vector<char> durch string ersetzen), das ist aber meines Wissens nicht standardkonform.


  • Administrator

    ipsec schrieb:

    hanzpetr schrieb:

    - bietet die Klasse stream keine skip() Methode an? Dafür dynamisch Speicher zu reservieren, Daten einzulesen und sofort wieder wegzuwerfen ist, äh, suboptimal. Was passiert, wenn du die ersten 3GB einer Datei überspringen möchtest?

    ifstream bietet keine skip-Methode an, zumindest habe ich keine gefunden.

    http://www.cplusplus.com/reference/iostream/istream/seekg/

    Oder vielleicht gleich: std::istream::ignore 😉

    Grüssli



  • berniebutt schrieb:

    Der Code sieht für C++ grottenschlecht und viel zu umständlich aus!

    Ich kenne mich in Java nicht aus, nur C und C++. Du willst doch nur Folgen von Bytes einlesen. Das Byte-Gefrickel erscheint mir reichlich kompliziert.

    Teile einfach mal mit, was genau in der Datei ankommt.

    Ich lese GuitarPro5-Dateien ein, welche im groben so aufgebaut sind:

    - Dateiversion
    - Allgemeine Dateiinfos
    - Lyrics
    - PageSetup
    - TempoValue
    - Channels
    - MeasureHeaders
    - Tracks
    - Measures

    Das Problem tritt meistens bei den Channels auf. Dabei wird eine Schleife 64x durchlaufen und jeweils 1 Integer und 6 x 1 Byte eingelesen und danach 2 Bytes übersprungen.

    Manchmal tritt der Fehler beim 1. Channel auf, manchmal beim x-ten Channel und bei ein paar Dateien erst bei den Measures (wobei ich hier erst überprüfen muss, ob der Code stimmt). Bis inklusive den Channels stimmt der C++ Code mit dem aber Java Code überein.

    Ab dem Fehler ist übrigens auf EOF true.. was aber eigentlich nicht sein kann.

    Edit:
    danke, dravere 🙂



  • Das hilft schon einmal ein bisschen weiter, aber noch nicht vollständig. Ich und andere vermögen das Problem noch nicht nachzuvollziehen.

    Fragen:
    1. Hat die Datei einzelne Sätze oder nur eine lose Folge von Bytes?
    2. Gibt es evtl. eine feste Satzlänge?
    3. Gibt es evtl. einen nach Typen festgelegten Satzaufbau?
    4. Gibt es eine inhaltliche Beschreibung der Datei? Wenn ja, bitte Link darauf setzen zum Ansehen.



  • Danke an alle, das Problem hat sich inzwischen erübrigt. Ich bin auf ein älteres Dateiformat umgestiegen und damit scheint es jetzt zu funktionieren.


Anmelden zum Antworten