Search code examples
androidc++serializationfstream

C++ reading file in as binary stream, skipping byte, randomly, in middle


std::ifstream infile;
infile.open(fullfilename, std::ios::binary);
std::vector<unsigned char> byteVect;
if (!infile.fail()) {
    infile.seekg(0, std::ios_base::end);
    int flsz = infile.tellg();
    LOG("sz=%d, infile.fail() returned %d", flsz, infile.fail());
    infile.seekg(0, std::ios_base::beg);
    while (!infile.eof()) {
        unsigned char byte;
        infile >> byte;
        if (infile.fail()) break;
        byteVect.push_back(byte);
    }
    infile.close();
    LOG("Loaded %d bytes into buffer", byteVect.size());

I then log the buffer to logcat with my favourite home made library function. Lots of zeroes but it's early doors still.

The problem is that not all the bytes are read in this way. I find a missing byte in the middle of the stream and it's bye bye successfull deserialization. I know not all the bytes are read because sometimes (whenever it fails) the first log of flsz is one more than the next log of byteVect.size(). I know it happens in the middle because I am watching the hexdump of input and output (Game of Thrones it isn't).

I can't see what's wrong with my code but I'd previously just stuck to C style fopen fread fwrite but thought it time to evolve. I'm sure you'll find a million holes in my looping algo but I'm learning. Thanks and stuff.


Solution

  • There are quite a few problems with this code. Th main ones being that looping on eof() is usually wrong (SEE THIS POST) and for binary input you should not use >>. You should use read() (Reference) because >> skips spaces and may change line ending characters.

    Here is how I would go about this task:

    int main()
    {
        std::vector<unsigned char> byteVect;
    
        std::ifstream infile;
    
        // open file at the end (to get its length)
        infile.open("test.txt", std::ios::binary|std::ios::ate);
    
        if(!infile.is_open())
        {
            std::cerr << "Error opening file: " << "" << std::endl;
            return 1;
        }
    
        // tellg() gives is the file position
        // (and therefore length)
        byteVect.resize(infile.tellg()); // make our vector big enough
    
        if(!byteVect.empty())
        {
            infile.seekg(0); // move file position back to beginning
    
            if(!infile.read((char*)&byteVect[0], byteVect.size()))
            {
                std::cerr << "Error reading file: " << "" << std::endl;
                return 1;
            }
        }
    
        infile.close();
    
        std::cout << "Loaded " << byteVect.size() << " bytes into vector." << '\n';
    }