JhonneyV
JhonneyV

Reputation: 1

Issues with variable used in reading binary file

I'm writing some serial port code and need to read the contents of a file (in binary) to a variable. Starting from the example for "Binary files" at http://www.cplusplus.com/doc/tutorial/files/ , I try opening a .jpg file:

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

ifstream::pos_type size;
char * memblock;

int main () {
  ifstream file ("example.jpg", ios::in|ios::binary|ios::ate);
  if (file.is_open())
  {
    size = file.tellg();
    memblock = new char [size];
    file.seekg (0, ios::beg);
    file.read (memblock, size);
    file.close();

    cout << memblock << endl;

    delete[] memblock;
   }
 else cout << "Unable to open file";
 return 0;
}

However, only the first 4 characters (32 bits) are printed in the console.

What's particularly odd though is that using ostream::write() with that supposedly faulty variable "memblock" works perfectly:

ofstream fileOut ("writtenFile.jpg",ios::out|ios::binary);
fileOut.write(memblock,size);
fileOut.close();

ie it creates a new .jpg file.

So my question is why the memblock variable seems to only contain the first 4 characters.

Upvotes: 0

Views: 424

Answers (2)

James Kanze
James Kanze

Reputation: 154037

Hmmm. A quick glance at the page you cite shows that the author doesn't know much about IO in C++. Avoid it, since much of what it says is wrong.

For the rest: .jpg is not a text format, and cannot be simply output to cout. When you use <<, of course, the output stops at the first '\0' character, but all sorts of binary data may cause wierd effects: data may be interpreted as an escape sequence repositionning the cursor, locking the keyboard (actually happened to me once), etc. These problems will occur even if you use std::cout.write() (which will not stop at the '\0' character). If you want to visualize the data, your best bet is some sort of binary dump. (I use something like the following for visualizing large blocks of data:

template <typename InputIterator>
void
process(
    InputIterator       begin,
    InputIterator       end,
    std::ostream&       output = std::cout )
{
    IOSave              saveAndRestore( output ) ;
    output.setf( std::ios::hex, std::ios::basefield ) ;
    output.setf( std::ios::uppercase ) ;
    output.fill( '0' ) ;
    static int const    lineLength( 16 ) ;
    while ( begin != end ) {
        int                 inLineCount = 0;
        unsigned char       buffer[ lineLength ] ;
        while ( inLineCount != lineLength && begin != end ) {
            buffer[inLineCount] = *begin;
            ++ begin;
            ++ inLineCount;
        }
        for ( int i = 0 ; i < lineLength ; ++ i ) {
            static char const *const
                                separTbl [] =
            {
                " ", " ", " ", " ",
                "  ", " ", " ", " ",
                "   ", " ", " ", " ",
                "  ", " ", " ", " ",
            } ; 
            output << separTbl[ i ] ;
            if ( i < inLineCount ) {
                output << std::setw( 2 )
                       << static_cast< unsigned int >(buffer[ i ] & 0xFF) ) ;
            } else {
                output << "  " ;
            }
        }
        output << " |" ;
        for ( int i = 0 ; i != inLineCount ; ++ i ) {
            output << (i < lengthRead && isprint( buffer[ i ] )
                       ?   static_cast< char >( buffer[ i ] ) 
                       :   ' ') ;
        }
        output << '|' << std::endl ;
    }
}

(You'll also want to read into an std::vector<char>, so you don't have to worry about freeing the memory.)

Upvotes: 0

DrYap
DrYap

Reputation: 6647

There is probably a 0 in your binary data. cout is a text stream so looks at memblock as a string. If it reaches a null character then it thinks the string has finished.

See this for some help pin outputting binary data: How to make cout behave as in binary mode?

Upvotes: 1

Related Questions