Link to home
Start Free TrialLog in
Avatar of Brian Withun
Brian WithunFlag for United States of America

asked on

Import numbers / strings from a binary file

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



So
void __fastcall TMyForm::ExportPicks(AnsiString sFile, TStringGrid *pGrid)
{
                  DeleteFile(sFile);
    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());

      }

    }

    FileClose(iHandle);
}

Open in new window

Copy-of-Picks.txt
SOLUTION
Avatar of George Tokas
George Tokas
Flag of Greece image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Brian Withun

ASKER

Thanks for your input, both of you.  I'll be posting what I ended up using.
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);
            }
        }

        CloseTLPFile();
    }
}

Open in new window

>>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)...
SO:
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.
>>>> 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?