BYTE, WORD, DWORD Binary Files

Hi guys, I have that write an binary file a object of 40 Bytes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream.h>
#include <fstream.h>

using namespace std;

typedef unsigned char  BYTE; // 1byte
typedef unsigned short  WORD; // 2bytes
typedef unsigned long  DWORD; //4bytes

class evHeader{
private:
   BYTE code;                                                  //Código do evento
   DWORD time;                                                   //Data/Hora (time_t)
   DWORD emp_id;
   BYTE cid_id;
   DWORD pdv_id;                                                 //id do PDV
   WORD appver;                                                  //Versão da aplicação residente
   WORD amver;                                                   //Versão do am residente
   WORD osver;                                                   //Versão do sistema operacional
   char serialno[10];
   char subversao[2];
   BYTE ruf[8];
public:
evHeader();
void print();
};
// buider
evHeader :: evHeader(){
   code = 0x0;
   time = 0x0;
   emp_id = 0x0;
   cid_id = 0x0;
   pdv_id = 0x0;
   appver = 0x0;
   amver = 0x0;
   osver = 0x0;
}
// print object
void evHeader :: print(){
   cout << "Code: " << (int)code << endl;
   cout << "Time: " << time << endl;
   cout << "Eemp_id: " << emp_id << endl;
   cout << "Cid_id: " << cid_id << endl;
   cout << "Pdv_id: " << pdv_id << endl;
   cout << "Appver: " << appver << endl;
   cout << "Amver: " << amver << endl;
   cout << "Osver: " << osver << endl;
}
//----------------------------------------------------------------------------

int main(){
   ifstream fin;
   evHeader header;
   fin.open("TESTE.pdv", ios::in | ios:: binary);
   if(fin.fail() == 1) { cout << "FATAL ERROR!" << endl; exit(1); } // protection against fails
   fin.seekg(0, ios::beg); // set pointer
   fin.read((char *)&header,sizeof(evHeader));
   header.print();
system("pause");
return 0;
}


When I read my object file with the following sequence of bytes:

1
2
3
	0x02, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00


the method print() should print:

code: 2
Time: 268435457
Eemp_id: 0
Cid_id: 0
Pdv_id: 0
Appver: 0
Amver: 0
Osver: 0

However, this did not happen! the first attribute "Code" size = 1 byte, when placed in the file occupies 4 bytes instead of 1, pushing "time" for the fifth position of the file

how solve this problem?

thanks Euler Rithie (euler.sistemas@gmail.com)
the first attribute "Code" size = 1 byte, when placed in the file occupies 4 bytes instead of 1, pushing "time" for the fifth position of the file
Hm?
Code: 02
Time: 10 00 00 01
I don't see that.

By the way, reading and writing files straight from structures is pretty ugly.
Last edited on
Best to use a text-mode approach if you can. But if you need to read this binary file, try reading each of the fields separately.

[code]
fin.read((char*)&header.code,sizeof(BYTE));
//etc.
[code]
It is because you are playing with a class and not a POD. Google around "c++ serialization" for more.

In short, you should explicitly read/write every field from/to a binary file, and make sure to byte-format them yourself. You can do this through simple member functions.

Here are some nice functions for reading/writing integer values in little-endian format:
1
2
3
4
5
6
7
template <typename Word>
ostream& write_word( ostream& outs, Word value )
  {
  for (unsigned size = sizeof( Word ); size; --size, value >>= 8)
    outs.put( static_cast <char> (value & 0xFF) );
  return outs;
  }
1
2
3
4
5
6
7
template <typename Word>
istream& read_word( istream& ins, Word& value )
  {
  for (unsigned size = 0, value = 0; size < sizeof( Word ); ++size)
    value |= ins.get() << (8 * size);
  return ins;
  }


Now, read each field separately as already recommended to you:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void evHeader :: readbinary( istream& ins )
  {
  read_word( ins, code );
  read_word( ins, time );
  read_word( ins, emp_id );
  read_word( ins, cid_id );
  read_word( ins, pdv_id );
  read_word( ins, appver );
  read_word( ins, amver );
  read_word( ins, osver );
  ins.read( serialno, 10 );
  ins.read( subversao, 2 );
  for (unsigned n = 0; n < 8; n++) read_word( ins, ruf[ n ] );
  }

Things to remember:
- The serialno and subversao fields presume that the string is properly null-terminated in the file, or it simply does not require it. (This is exactly as it is with your original code).
- The ruf array could have been read with istream::read() also, but I put in the example in case you find yourself loading an array of WORD or DWORD.
- Be sure to check your input stream for errors afterwards... the read_word() doesn't report them, but if, for example, you hit EOF before an entire word (BYTE, WORD or DWORD) is read, the result will not have a useful value.

Hope this helps.
Last edited on
Topic archived. No new replies allowed.