Go to a certain point of a binary file in C (using fseek) and then reading from that location (using fread)

user1291631 picture user1291631 · Mar 25, 2012 · Viewed 15.9k times · Source

I am wondering if this is the best way to go about solving my problem.

I know the values for particular offsets of a binary file where the information I want is held...What I want to do is jump to the offsets and then read a certain amount of bytes, starting from that location.

After using google, I have come to the conclusion that my best bet is to use fseek() to move to the position of the offset, and then to use fread() to read an amount of bytes from that position.

Am I correct in thinking this? And if so, how is best to go about doing so? i.e. how to incorporate the two together.

If I am not correct, what would you suggest I do instead?

Many thanks in advance for your help.

Matt

Edit:

I followed a tutorial on fread() and adjusted it to the following:

    `#include <stdio.h>
    int main()
    {
      FILE *f;
      char buffer[11];
      if (f = fopen("comm_array2.img", "rt"))
      {
        fread(buffer, 1, 10, f);
        buffer[10] = 0;
        fclose(f);
        printf("first 10 characters of the file:\n%s\n", buffer);
      }
      return 0;
    }`

So I used the file 'comm_array2.img' and read the first 10 characters from the file.

But from what I understand of it, this goes from start-of-file, I want to go from some-place-in-file (offset)

Is this making more sense?

Edit Number 2:

It appears that I was being a bit dim, and all that is needed (it would seem from my attempt) is to put the fseek() before the fread() that I have in the code above, and it seeks to that location and then reads from there.

Answer

Jonathan Leffler picture Jonathan Leffler · Mar 25, 2012

If you are using file streams instead of file descriptors, then you can write yourself a (simple) function analogous to the POSIX pread() system call.

You can easily emulate it using streams instead of file descriptors1. Perhaps you should write yourself a function such as this (which has a slightly different interface from the one I suggested in a comment):

size_t fpread(void *buffer, size_t size, size_t mitems, size_t offset, FILE *fp)
{
     if (fseek(fp, offset, SEEK_SET) != 0)
         return 0;
     return fread(buffer, size, nitems, fp);
}

This is a reasonable compromise between the conventions of pread() and fread().


What would the syntax of the function call look like? For example, reading from the offset 732 and then again from offset 432 (both being from start of the file) and filestream called f.

Since you didn't say how many bytes to read, I'm going to assume 100 each time. I'm assuming that the target variables (buffers) are buffer1 and buffer2, and that they are both big enough.

if (fpread(buffer1, 100, 1, 732, f) != 1)
    ...error reading at offset 732...
if (fpread(buffer2, 100, 1, 432, f) != 1)
    ...error reading at offset 432...

The return count is the number of complete units of 100 bytes each; either 1 (got everything) or 0 (something went awry).

There are other ways of writing that code:

if (fpread(buffer1, sizeof(char), 100, 732, f) != 100)
    ...error reading at offset 732...
if (fpread(buffer2, sizeof(char), 100, 432, f) != 100)
    ...error reading at offset 432...

This reads 100 single bytes each time; the test ensures you got all 100 of them, as expected. If you capture the return value in this second example, you can know how much data you did get. It would be very surprising if the first read succeeded and the second failed; some other program (or thread) would have had to truncate the file between the two calls to fpread(), but funnier things have been known to happen.


1 The emulation won't be perfect; the pread() call provides guaranteed atomicity that the combination of fseek() and fread() will not provide. But that will seldom be a problem in practice, unless you have multiple processes or threads concurrently updating the file while you are trying to position and read from it.