Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Read binary data from file



  • Hi everyone !

    I am trying to read data from a file that can be either in ascii or binary format. For the ascii one, I figured out a code to read it and get the data. But I'm stuck with the binary format.

    My binary file contain a 80 bytes header wich is a string, and then a 4 bytes unigned int that correspond to the data length, followed by the data. I've tried differents approach :

    QFile file(file_name);
    
    if (!file.open(QIODevice::ReadOnly))
            return;
    
    QDataStream s(&file);
    s.setByteOrder(QDataStream::LittleEndian);
    char *buffer = new char[4];
    
    s.skipRawData(80);    // I've already read the header before to determine the file format
    s.readRawData(buffer,4);
    ulong length = ulong(buffer);
    qDebug() << length;
    

    But the value returned is totaly inconsistent and change each time I run my code, wich makes me seriously doubt its validity.
    Other way tested :

    file.seek(80);
    ulong length =  file.read(4).toULong();
    qDebug() << length;
    

    But it return 0 every time.
    And the last one :

    QDataStream s(&file);
    s.setByteOrder(QDataStream::LittleEndian);
    
    ulong length;
    s >> length;
    qDebug() << length;
    

    But it also return 0.

    Do you have any idea of what I am doing wrong ? If differents ways exist, wich one is the fastest ?
    Thank you for your help !

    HB76


  • Lifetime Qt Champion

    Hi,

    @HB76 said in Read binary data from file:

    ulong length = ulong(buffer);

    You are casting a pointer to a char array to ulong not its content. That's why you get a different value every time. You are seeing the address of the first item of that array.



  • You can use pointers to do this sort of thing. I have an example that takes some part of a QByteArray and extracts an integer from it:

    int i;
    char *c;
    		
    c = (char*)(&i); // set address of char to point to address of integer.  The two are now tied together
    	
    // indirectly copy bytes to integer.  Var 'index' is first byte of integer value in the byte_array
    for(unsigned int cntr = 0;cntr < sizeof(int);++cntr)
        *(c + cntr) = array[index + cntr];
    	
    // var 'i' now contains integer value
    


  • Thank you for your response,

    indeed I noticed the pointer problem in my code, but even when I use the normal variable, the value returned is not correct :

    QDataStream s(&file);
    s.setByteOrder(QDataStream::LittleEndian);
    char buffer[4];
    
    s.skipRawData(80);
    s.readRawData(buffer,4);
    ulong length = ulong(buffer);
    qDebug() << length;
    

    Should return 70540 in this case but return 2686300.
    Same for :

    QDataStream s(&file);
    s.setByteOrder(QDataStream::LittleEndian);
    char *buffer = new char[4];
    
    s.skipRawData(80);
    s.readRawData(buffer,4);
    ulong length = ulong(*buffer);
    qDebug() << length;
    

    wich return 0...

    I would just like to understand what is incorrect in this code to know what I am doing wrong



  • @HB76 said in Read binary data from file:
    ulong length = ulong(*buffer);

    only looks at the first char/byte in buffer, i.e. buffer[0], and that's probably a 0, so that's not much good!

    As for ulong length = ulong(buffer); not returning what you expect, the first thing I'd do is print it out in hex rather than decimal/look at the 4 bytes and see if they are the wrong way round/not what you expect in the 4 bytes. [I'm tired now, but doesn't ulong(buffer) just do the same thing as (ulong)buffer, and hence all you're printing is the address of the variable and nothing about its content?]

    Apart from that, and I haven't looked up the mechanics, but I don't see how QDataStream::setByteOrder() can cooperate with your choice of using QDataStream::readRawData(). If it reads raw bytes it's not going to be dealing with numbers and observing any byte ordering. Presumably you have to use QDataStream &QDataStream::operator>>(quint32 &i), https://doc.qt.io/qt-5/qdatastream.html#operator-gt-gt-5, if you want to read what you know to be numbers and have the byte order taken into account.



  • QDataStream s(&file);
    s.setByteOrder(QDataStream::LittleEndian);
    
    s.skipRawData(80);
    qint32 value;
    s >> value;
    qDebug() << value;
    

    give me the same result, 0...



  • @HB76 just in case, could you please post:

    1. the values of the bytes at positions 80, 81, 82, 83 for the file you're working with?
    2. the size of the data (or the whole file) for such file?


  • I've found a way to do it :

    QByteArray data = file.read(4);
    qint32 facet_count;
    memcpy(&facet_count, data.constData(), 4);
    qDebug() << facet_count;
    

    Just for knowledge, why this simple code doesn'y work ?

    file.seek(80);
    ulong length =  file.read(4).toULong();
    qDebug() << length;
    

    it would be much more simplier..


  • Qt Champions 2019

    @HB76 said in Read binary data from file:

    ulong length = file.read(4).toULong();

    Because you did not read the documentation: https://doc.qt.io/qt-5/qbytearray.html#toLong



  • @Pablo-J-Rogina the values are :

    80 : "\x8C"
    81 : "\x13"
    82 : "\x01"
    83 : "\x00"

    the file length is 3527084 using

    int length = int(file.size());
    


  • @Christian-Ehrlicher I was just having a look at it but I supposed I didn't understand the whole explaination the first time as I'm not native english ^^'


  • Qt Champions 2019

    The example there should be obvious:

    QByteArray str("FF");
    bool ok;
    int hex = str.toInt(&ok, 16);     // hex == 255, ok == true
    int dec = str.toInt(&ok, 10);     // dec == 0, ok == false
    

    As you can see it converts a string value into an integer



  • ok I got it now, but why every time the conversion failed with this method whereas the conversion with memcpy is working ?


  • Qt Champions 2019

    @HB76 said in Read binary data from file:

    ut why every time the conversion failed with this method whereas the conversion with memcpy is working ?

    Again: toUint() interprets your string as ascii text and tries to convert it to an integer, whereas memcpy simply copies the plain data - C basics on how a value is interpreted.



  • Ok thank you very much !
    I don't know if it is the most efficient way to read data but it is working !


Log in to reply