Harpreet Singh Sethi
Harpreet Singh Sethi

Reputation: 53

reading Binary files

I want to read this binary file and print the numbers on the screen but it is printing weird characters. I generated this binary file from MATLAB. How can I display the data properly?

#include <iostream>
#include <fstream>
using namespace std;

ifstream::pos_type size;
char * memblock;

int main ()
{
   ifstream file ("seg.bin", ios::in|ios::binary|ios::ate);

   if (file.is_open())
   {
        size = (int)file.tellg();
        memblock = new char [size];
        file.seekg (0, ios::beg);
        file.read (memblock, size);
        file.close();

        cout << "the complete file content is in memory";

        for (int i=0;i<size;i++)
        {
            cout<<memblock[i]<<endl;
        }
    }
    else cout << "Unable to open file";
    return 0;
}

Upvotes: 2

Views: 1469

Answers (3)

PaperBirdMaster
PaperBirdMaster

Reputation: 13298

You're printing chars to the output, the representation of the char in the output is a character, and if the character you're sending to std::cout isn't printable you'll see nothing or in some cases you'll see weird characters (or in some cases a beep sound!).

Try to cast the char value to int:

std::cout << static_cast<int>(memblock[i]) << std::endl;
             ^^^^^^^^^^^^^^^^

The way you're iterating-printing the data you'll only get data of 8bits size (or the size you char is), let's supose you have the following data on your file:

00000FFF

Your output will be:

0

0

15

255

But if you're working with data of other sizes (int for example) you will expect an output of 4095 (or 0 and 4095 if your data is 16bits wide).

If is your case, try to read the data into an array of the data you're expecting:

const ifstream::pos_type size = file.tellg(); // do not cast the size!
const size_t elements = size / sizeof(int);   // <--- beware of the sizes!
memblock = new int [elements];                // Elements, not size

for (int i = 0; i < elements; ++i) // Elements! not size
{
    std::cout << memblock[i] << std::endl;
}

Another tips:

  • Declare size and elements as const (you're not going to change them after reading): This shows to you and your workmates your intention to treat this variables as read-only.
  • Do not cast size to int, use the type of return of tellg() or use auto: const auto size = file.tellg();: Why cast to another type? Use the same of the function you're calling! Casts may lead to overhead.
  • Try to declare your variables in the tiniest scope and near the place you're going to use them: This will make your code more readable and maintainable.

Upvotes: 0

Ivan Lebediev
Ivan Lebediev

Reputation: 537

memblock is of type char that is why cout will make char print(ascii characters). What you want to in this case is to reinterpret_cast the memblock pointer to the pointer of the type that you need. Say you need double:

size = (int)file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
double * fileContent = reinterpret_cast<double *>(memblock);
cout << "the complete file content is in memory";

int sizeOfFileContent = sizeof(memblock)/sizeof(double);
for (int i=0; i<sizeOfFileContent; i++)
{
   cout<<fileContent[i]<<endl;
}

Use only one pointer to reclaim memory, not to try to delete it multiple times!

Upvotes: 0

paddy
paddy

Reputation: 63481

You need to know what the datatype stored in the file is. Let's say it's double. In that case, you can do this:

for (int i = 0; i < size; i += sizeof(double))
{
    cout << *(double*)&memblock[i] << endl;
}

The other way to go about it is to read directly into an array of double to begin with. Will leave that as an exercise.

Upvotes: 0

Related Questions