Import numbers / strings from a binary file

Posted on 2009-12-18
Last Modified: 2013-11-17
I've attached a copy of the file I'm trying to import.  I've renamed it to a .TXT so that EE will allow me to attach it, but it's not a text file.

The attached code was used to create this file, and I'd like to come up with similar code that will allow me to import the file back into the program.

I'm just not a File I/O guy.  I need some help, preferably a solution that uses FileOpen() and FileRead() to get it done.

The first 4 bytes of this file are 06 00 00 00, and they represent an integer, 6.  The second 4 bytes are 7C 02 00 00, which represent the number 636.  The remainder of the file contains 3,816 values (6x636).

The first "value" is a 1, and it's stored as a 4-byte length (01 00 00 00) and the ascii value of the digit "1", (31)

The second value is another 5 bytes .. 01 00 00 00 31 .. this is another "1"

The third value is also 5 bytes.. 01 00 00 00 32 .. this represents a "2"

..hopefully this is clear.  I'm sure you can figure out the data layout by looking at the ::ExportPicks() method.

Can someone write for me the body of this method?

void __fastcall TMyForm::ImportPicks(AnsiString sFile, TStringGrid *pGrid)
    /* help */

Thanks in advance...
Brian Withun

void __fastcall TMyForm::ExportPicks(AnsiString sFile, TStringGrid *pGrid)



    int iHandle = FileCreate(sFile);

    int iLength = 0;

    FileWrite(iHandle, (char*)&(pGrid->ColCount), sizeof(pGrid->ColCount));

    FileWrite(iHandle, (char*)&(pGrid->RowCount), sizeof(pGrid->RowCount));

    for (int y=0; y<pGrid->RowCount; y++)


        for (int x=0; x<pGrid->ColCount; x++)


        // Write out the length of each string, followed by the string itself.

        iLength = pGrid->Cells[x][y].Length();

        FileWrite(iHandle, (char*)&iLength, sizeof(iLength));

        FileWrite(iHandle, pGrid->Cells[x][y].c_str(), pGrid->Cells[x][y].Length());





Open in new window

Question by:Brian Withun
    LVL 16

    Assisted Solution

    by:George Tokas
    Load the file in a buffer.
    In order to prevent memory leaks declare the buffer globally at your main header file...

    BYTE     *pszBuffer;

    At the code:
    Assuming that the file has a fixed size i.e. 256bytes, at forms constructor:
    pszBuffer = new BYTE[256];
    //zero all contents
    for(int i = 0; i < 256; i++){pszBuffer[i] = 0;}

    Load the file:
    int iFileHandle;
    iFileHandle = FileOpen("myfile.ext",fmOpenRead);//Just for reading and prevent mistakes
    //trap error
    if(iFileHandle < 0)
    //read the content
    FileRead(iFileHandle, pszBuffer, 256);
    //The content is loaded at pszBuffer[]
    //Close the file because we are done...

    The content of the file is now inside pszBuffer that is an array and you can access it the way you like...
    For myself I'm a fun of accessing every byte inside and do what I like.
    In this example you can access the byte at location 0x10 using:
    unsigned char a = 0;//or BYTE a if you like... we will just read or write the hex content of the location
    a = pszBuffer[0x10];
    Do not read/write integers or 64bit integers using the buffer...
    Better assemble an integer from the 4 bytes inside the buffer. Same when saving...
    Maybe more code but safer in cases of leak or bugs.

    George Tokas.

    LVL 16

    Expert Comment

    by:George Tokas
    The answer is generic just to saw you the way...
    In case of pictures as I see to your code since the file has not a fixed size.
    Calculate the size of the file and store it as an __int64 (8bytes) in the begining of the buffer.
    In this case (file size not fixed) the buffer has to be declared, initialized, destroyed at runtime.
    1. Read the file as showed, AND CLOSE THE FILE.
    2. Read the first 8 bytes and construct the __int64 of the size of the file.
    3. BYTE *pszBuffer2 = new BYTE[(the __int64 constructed)];
    4. Read the file again using: FileRead(iFileHandle, pszBuffer2, (the __int64 constructed)); AND CLOSE THE FILE AGAIN!!
    5. Do your job with the buffer and delete it...

    The reason I'm telling you to close the file is to avoid pointer to start reading of the file mistakes.

    George Tokas.
    LVL 39

    Accepted Solution

    You may try the code below. Unfortuanetly I neither could find out how to propely resize a TStringGrid nor how to update the string of a specific cell.

    #include <fstream>
    using namespace std;
    // assume the grid passed is already proper sized ?
    int readData(const char * pszFile, TStringGrid & grid)
        ifstream ifs(pszFile, ios::binary, ios::in);
        int n1 = 0;
        int n2 = 0;
        if (!*)&n1, 4))
            return -1;
        if (!*)&n2, 4))
            return -1;
        if (n1 > grid.ColCount)
            return -2;
        if (n2 > grid.RowCount)
            return -3;
        int  n      = 0;
        char cb[32] = { '\0' };
        for (int r = 0; r < n2; ++r)
            for (int c = 0; c < n1; ++c)
                if (!*)&n, 4))
                    return -1;
                if (n >= 32 || !, n))
                    return -1;
                grid.Cells[r][c] = cb;   // Is that the right statement? 
        return 0;

    Open in new window

    LVL 13

    Author Closing Comment

    by:Brian Withun
    Thanks for your input, both of you.  I'll be posting what I ended up using.
    LVL 13

    Author Comment

    by:Brian Withun
    My "Export" code came right out of the "Help" from Borland C++ Builder 5.  The example for FileWrite() matched my needs almost exactly.  That was a stroke of luck.

    The help page for FileRead(), however, had an unrelated example and so I couldn't use it.  I didn't exactly understand how the FileWrite() example worked, so I posted it to see if it was something anyone else was familiar with.

    Specifically, the way to get a string OUT of the TStringGrid and INTO the file was unfamiliar.  I hadn't figured out how to reverse that technique for the import method.

    Since posting the original question, I believe I have figured it out.  It seems unorthodox to cast an &int to a char*, but that was how the Borland example worked, and it appears to work fine in my implemention of ::Import().

    I appreciate the input provided by both of the experts who responded.
    void __fastcall TMyForm::Import(void)
        AnsiString sFile = GetFilename();
        if (OpenTLPFile(sFile))
            FileRead(iHandle, (char*)&(PicksGrid->ColCount), sizeof(PicksGrid->ColCount));
            FileRead(iHandle, (char*)&(PicksGrid->RowCount), sizeof(PicksGrid->RowCount));
            int iLength;
            for (int y=0; y<PicksGrid->RowCount; y++)
                for (int x=0; x<PicksGrid->ColCount; x++)
                    FileRead(iHandle, (char*)&iLength, sizeof(iLength));
                    PicksGrid->Cells[x][y] = ReadTLPFile(iLength);

    Open in new window

    LVL 16

    Expert Comment

    by:George Tokas
    >>FileRead(iHandle, (char*)&iLength, sizeof(iLength));
    You are reading iLength bytes of data from the file and loading them at iLength that is an int and means 4 bytes...
    AFTER that line the file pointer ( the location the file is about to read again ) is incremented by iLength (4 bytes)...
    What you are doing here is a serialized read from the file...

    What I was proposed is to load the content inside a buffer and release the file...
    I don't mean that my approach is better, but in case of an exception you don't have to worry about the file handle (iHandle)...
    On the other hand coding using the buffer, even though safer IMHO, needs a lot more of coding...

    George Tokas.
    LVL 39

    Expert Comment

    >>>> It seems unorthodox to cast an &int to a char*,

    No, that's quite common for functions coming from a C interface.  C functions cannot have overloads for poimnters of different types but have a void* or char* (or unsigned char*) which must be casted.

    >>>> Specifically, the way to get a string OUT of the TStringGrid and INTO the file was unfamiliar.
    That was the way text files were stored before termination by linefeed characters became standard.

    >>>> PicksGrid->Cells[x][y] = ReadTLPFile(iLength);
    What is ReadTLPFile?

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Looking for New Ways to Advertise?

    Engage with tech pros in our community with native advertising, as a Vendor Expert, and more.

    Suggested Solutions

    Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
    Displaying an arrayList in a listView using the default adapter is rarely the best solution. To get full control of your display data, and to be able to refresh it after editing, requires the use of a custom adapter.
    The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
    The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

    758 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    10 Experts available now in Live!

    Get 1:1 Help Now