Thread: Help getting into the right direction with binary files.

  1. #1
    Registered User
    Join Date
    Jan 2009
    Location
    Sweden
    Posts
    8

    Help getting into the right direction with binary files.

    Im trying a little mini project just because I got curious. I want to try to make a archive like file except nothing will be encrypted or compressed. My idea was the use the C++ filestream classes to read and write data from this archive file. To keep it simple I thought having a file structure that looked like this structure below would be a good start.

    File structure:
    sizeOfFile1
    file1Name
    file1Data
    sizeOfFile2
    file2Name
    file2Data
    .
    .
    .

    But I have run into a little problem. My first approach is to get in idea how my functions would be like so I made a small program where I told the program to put a file into a archive file (only a single file would be archived) and then do the reverse. So in short just making a long way to make a copy of a file twice.

    I was able to do this with
    Code:
    outdata << indata.rdbuf();
    I got a working copy. But the problem with this approach is that Im not able to read parts of a file.

    This approach could work when archiving files by first writing a long representing the size of the file and then an fixed size array for the file name. Then after that use outdata << indata.rdbuf(); to write from the source file into my archive file and then repeat the process for each file.

    But to unarchive this I would need to first read the size of a long, and then the size of my fixed array. And then use that long to read the right amount of data that will be the file itself and then output it. But I havenīt been able to do this by using either read, get or wrote. Im able to extract the long and the array. Atleast I have been able to in other mini projects. But I seem unable to extract the file even when itīs only the file that is stored inside the archive.

    My approach to this it that I first get the file size of the file. (I have checked and I seem to get the right size)
    Code:
    // begin, end and size are of the type long
    begin = indata.tellg();
    indata.seekg(0, ios::end);
    end = indata.tellg();
    size = end - begin;
    Then I would make a char array and use it as a buffer to store the data while reading the file. But I think itīs here I have my problem.
    Code:
    // buffer is the char array and fileSize is the size of the file in bytes. With mingw on my 
    // computer one char is 1 byte, so I made the char array with fileSize(in bytes) elements
    indata.read(reinterpret_cast<char*>(&buffer), fileSize);
    I use binary mode when I do this. When I use write to write the the output file from this buffer I get a file with the right size but that is corrupted. So Im sure I do something wrong here and itīs here I need your help to get my into the right direction.

    How should I tackle this so I get the result that I want? My idea was the read a file in binary mode, save it inside another file, and now while "archiving" a single file I would be just making a copy with another extension. And then reverse the process. By renaming the output file back to the same extension as the original file I found that the file is corrupted. So I need some advice how to read the file in a proper way so I donīt miss any data and then not getting any corrupted files.

    I do understand that it would be stupid to try large files because it would eat my memory so Im sticking to small files for now and will work on a way to read and write piece by piece later when I get this working. So far itīs only in testing and trying out stage.



    This is just a project Im doing to learn a little more and just play around with. Not because I try to archive files for a real life use. At least not yet but who knows how things will be in the future. The one who lives will know.

  2. #2
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    I think you may be confused about how to use istream::read().

    Code:
    char buffer[fileSize];
    indata.read( buffer, fileSize );

  3. #3
    Registered User
    Join Date
    Jan 2009
    Location
    Sweden
    Posts
    8
    I have tried that too and I get the same result. I just get a corrupt file after sending it through my test program.

    So my question now is, is it possible to copy the file by using read and store it into a char array in binary mode and then use write in binary mode to write to the output file and not missing any data that makes the file corrupt?

    I think thatīs the first question I need to solve to move on.

    My source code right now is: (This is just a test program so all code is inside main for the moment)
    Code:
    // Packer program, the unpacker works the same except that you also gives the output file an
    // extension for example test.jpg
    #include <iostream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char* argv[])
    {
        if(argc == 1)
        {
        	cout << endl << "No files to pack" << endl << endl << "Press return to exit";
            cin.get();
            return 1;
        }
        
        long begin, end, size = 0;
        string fileName;
        
        cout << "Enter output file name: ";
        getline(cin, fileName);
        fileName = fileName += ".pak";
        
        // Opening the files works
        ifstream indata(argv[1], ios::binary);
        ofstream outdata(fileName.c_str(), ios::binary);
        
        // Get the file size. It gives me the right number in bytes
        begin = indata.tellg();
        indata.seekg(0, ios::end);
        end = indata.tellg();
        size = end - begin;
        
        // Here I make my buffer, a char array with the size of size.
        char buffer[size];
        
        // First I use my ifstream to read the data and store it in my buffer, after that I use my ofstream to write the data
        indata.read(buffer, size);
        outdata.write(buffer, size);
        
        indata.close();
        outdata.close();
        
        return 0;
    }

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    When I compile your code I get the following warning:

    main.cpp||In function ‘int main(int, char**)’:|
    main.cpp|36|warning: ISO C++ forbids variable length array ‘buffer’|
    ||=== Build finished: 0 errors, 1 warnings ===|

    You might try to dynamic memory allocation for your buffer (new/delete).

    Jim

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by jimblumberg
    You might try to dynamic memory allocation for your buffer (new/delete).
    It would be better to #include <vector> and then write:
    Code:
    std::vector<char> buffer(size);
    
    // First I use my ifstream to read the data and store it in my buffer, after that I use my ofstream to write the data
    indata.read(&buffer[0], size);
    outdata.write(&buffer[0], size);
    Though there should be a check to ensure that size is positive.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Your problem is that you are leaving the seek pointer at the end of the file, so read() has nothing left to read. Reset the pointer to the beginning of the file:

    Code:
        // ...
        indata.seekg(0);
        indata.read(buffer, size);
        outdata.write(buffer, size);
        // ...

  7. #7
    Registered User
    Join Date
    Jan 2009
    Location
    Sweden
    Posts
    8
    jimblumberg:
    When I compile your code I get the following warning:

    main.cpp||In function ‘int main(int, char**)’:|
    main.cpp|36|warning: ISO C++ forbids variable length array ‘buffer’|
    ||=== Build finished: 0 errors, 1 warnings ===|

    You might try to dynamic memory allocation for your buffer (new/delete).
    Thatīs why I used my approach that I wrote in my first post.

    It would be better to #include <vector> and then write:
    CODE
    Though there should be a check to ensure that size is positive.
    I tried using a vector this way now and it works. Thanks for the tip. Because this is just a test program I havenīt include any size check or any error checks at all almost. But when I know I got each part working I will include error checking.

    R.Stiltskin:
    Your problem is that you are leaving the seek pointer at the end of the file, so read() has nothing left to read. Reset the pointer to the beginning of the file:
    Why didnīt I think of that? Thanks for pointing that out. Its working like a charm now.

    Thanks everyone. Now I can continue experimenting.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. added start menu crashes game
    By avgprogamerjoe in forum Game Programming
    Replies: 6
    Last Post: 08-29-2007, 01:30 PM
  2. Processing binary or plaintext files
    By Jags in forum C Programming
    Replies: 12
    Last Post: 08-04-2006, 02:35 PM
  3. Linking header files, Source files and main program(Accel. C++)
    By Daniel Primed in forum C++ Programming
    Replies: 3
    Last Post: 01-17-2006, 11:46 AM
  4. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  5. send/recv binary files using sockets in C++
    By dafatdude in forum Networking/Device Communication
    Replies: 14
    Last Post: 07-25-2004, 11:00 AM