tags:

views:

346

answers:

5

Here is the snippet of code

typedef struct
{
   double testA;
   double testB[500];   
   bool isProcessed;
} MYSTURCT;

I have a binary file which is written with multiple structs of type "myStruct".

Now, in another function, I m trying to read the file and update in the middle.

void test()
{
    FILE* fp = fopen (testFile, "r+")

    MYSTURCT* myPtr = malloc (sizeof (MYSTRUCT));

    while ( fread (myPtr,sizeof(MYSTRUCT),1,fp) )
    {
        if (!myPtr->isProcessed)
        {
            //update some thing int he struct

            myPtr->testA = 100.00;

            fseek (fp, -sizeof(MYSTRUCT), SEEK_CUR);

            fwrite (myPtr,sizeof(MYSTRUCT), 1,fp);

        }
    }
}

Once I find something unprocessed, I update the struct in the memory, then try to write the struct to the disk. (first by seeking the CURR - sizeof(struct)) position and then fwriting the struct to disk.

Whats happening in my application is after doing the fseek, my

fp->_ptr is getting messed up and it looses the track of position in my stream.

Is there anything wrong that I am doing here?

+2  A: 

The fopen manpage says:

Reads and writes may be intermixed on read/write streams in any order. Note that ANSI C requires that a file positioning function intervene between output and input, unless an input operation encounters end-of- file. (If this condition is not met, then a read is allowed to return the result of writes other than the most recent.) Therefore it is good practice (and indeed sometimes necessary under Linux) to put an fseek(3) or fgetpos(3) operation between write and read operations on such a stream. This operation may be an apparent no-op (as in fseek(..., 0L, SEEK_CUR) called for its synchronizing side effect.

So you might try putting the dummy fseek in right after you fwrite.

kwatford
The problem that seems to happen is, my fp->_ptr which actually stores the pointer to the location in the file gets corrupted immediately after doing fseek. Even when I donot do fwrite, just doing fseek is creating problem. My struct is a big struct with multiple elements. I am trying to figure out if I am providing the wrong argument in the size. But not sure.
Jitesh Dani
You seem to have misspelled MYSTRUCT in a few places. Hopefully that's just an issue with your post and not your code :). If you don't mind, try putting in a "long offset = -sizeof(MYSTRUCT)" in before the seek and then print that value. sizeof normally returns an unsigned number, but hopefully your compiler can figure that out...
kwatford
+1  A: 

Try fflush after the last fwrite(). Then Try making a new test file using your current structure. It could be that you changed your structure and your current test file has an older invalid byte order.

Tim Santeford
Could it be that the "bool isProcessed" is not using up a complete 32 bits. It there a byte boundary issue? Did you reorder the types inside the MYSTURCT struct. If so start with a newly created file.
Tim Santeford
Make a new test file based on your latest build and do the temporary char substitution that rascher did to make the struct fill the byte boundary.
Tim Santeford
This did the trick. The inherent problem was fwrite followed by fread as mentioned by kwatford in the earlier answer. To solve the issue, I just put fflush() after fwrite and it worked.WHen I was debugging, I was looking at fp->_ptr value and I think, it was not a good idea. FSEEK doesnot set this value after the call. To me, I assumed it was corrupted (which was not)
Jitesh Dani
A: 

I tried your sample code, and it seems to work fine to me (though I am doing it in C - I substituted a "char" for your "boolean")

For debugging, how do you know that the fp is getting corrupted? It is unusual to look at the members of the FILE struct. Each time you do an fseek(), fread() or fwrite(), what is your output when you invoke ftell()?

rascher
I started my task in the debugger and put a break pt, that was one way I came to know it was getting corrupted. Other way, I printed fp->_ptr in hex before and after..
Jitesh Dani
+1  A: 

You malloc sizeof (MYSTRUCT) bytes to myPtr, but myPtr is of type MYSTURCT.

I don't think that's your problem, though.

Apparently there's nothing wrong with your code; try to add some error-checking ...

void test(){
    FILE* fp = fopen (testFile, "r+"); /* missing semicolon */
    MYSTURCT* myPtr = malloc (sizeof *myPtr);
    while ( fread (myPtr,sizeof *myPtr,1,fp) == 1) /* error checking */
    {
        if (!myPtr->isProcessed)
        {
            //update some thing int he struct
            myPtr->testA = 100.00;
            if (fseek (fp, -sizeof *myPtr, SEEK_CUR) == -1)
            {
                perror("fseek");
            }
            if (fwrite (myPtr,sizeof *myPtr, 1,fp) != 1)
            {
                perror("fwrite");
            }
        }
    }
}

And the fopen should be in binary mode, even if you're on Linux (where it really doesn't matter). On Windows a sequence of 0x0D 0x0A in the middle of one of those doubles will get converted to 0x0D and mess everything up.

pmg
+3  A: 

-sizeof(STRUCT) is potentially dangerous. sizeof(STRUCT) is an unsigned type, and if it is as least as wide as an int it's promoted type (the type of the -sizeof(STRUCT) expression) will also be unsigned and have a value of about UINT_MAX - sizeof(STRUCT) + 1 or possibly ULONG_MAX - sizeof(STRUCT)+ 1.

If you're unlucky (e.g. 32 bit size_t, 64 bit long) its UINT_MAX - sizeof(STRUCT) + 1 and a long int may be able to hold this large postive value and the seek won't do what you want it to do.

You could consider doing a position save and restore:

fpos_t pos;

if (fgetpos(fp, &pos) != 0)
{
    /* position save failed */
    return;
}

/* read struct */

if (fsetpos(fp, &pos) != 0)
{
    /* position restore failed */
    return;
}

/* write struct */

fgetpos and fsetpos use a fpos_t so can potentially work with very large files in scenarios where fseek and ftell won't.

Charles Bailey
A question I asked last month touches on this issue: http://stackoverflow.com/questions/1269019
Novelocrat