C Tutorial – Binary File I/O

In an earlier tutorial we talked about file I/O functions and the use of text files. In this C programming tutorial we are going to talk about the use of binary files.

Binary files

Binary files are very similar to arrays of structures, except the structures are in a disk-file rather than an array in memory. Binary files have two features that distinguish them from text files:

  • You can instantly use any structure in the file.
  • You can change the contents of a structure anywhere in the file.

After you have opened the binary file, you can read and write a structure or seek a specific position in the file. A file position indicator points to record 0 when the file is opened.

A read operation reads the structure where the file position indicator is pointing to. After reading the structure the pointer is moved to point at the next structure.

A write operation will write to the currently pointed-to structure. After the write operation the file position indicator is moved to point at the next structure.

The fseek function will move the file position indicator to the record that is requested.

Remember that you keep track of things, because the file position indicator can not only point at the beginning of a structure, but can also point to any byte in the file.

The fread and fwrite function takes four parameters:

  • A memory address
  • Number of bytes to read per block
  • Number of blocks to read
  • A file variable

For example:


     fread(&my_record,sizeof(struct rec),1,ptr_myfile);

This fread statement says to read x bytes (size of rec) from the file ptr_myfile into memory address &my_record. Only one block is requested. Changing the one into ten will read in ten blocks of x bytes at once.

Let’s look at a write example:


	#include<stdio.h>

	/* Our structure */
	struct rec
	{
		int x,y,z;
	};

	int main()
	{
		int counter;
		FILE *ptr_myfile;
		struct rec my_record;

		ptr_myfile=fopen("test.bin","wb");
		if (!ptr_myfile)
		{
			printf("Unable to open file!");
			return 1;
		}
		for ( counter=1; counter <= 10; counter++)
		{
			my_record.x= counter;
			fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);
		}
		fclose(ptr_myfile);
		return 0;
	}

In this example we declare a structure rec with the members x,y and z of the type integer. In the main function we open (fopen) a file for writing (w). Then we check if the file is open, if not, an error message is displayed and we exit the program. In the “for loop” we fill the structure member x with a number. Then we write the record to the file. We do this ten times, thus creating ten records. After writing the ten records, we will close the file (don’t forget this).

So now we have written to a file, let’s read from the file we have just created. Take a look at the example:


	#include<stdio.h>

	/* Our structure */
	struct rec
	{
		int x,y,z;
	};

	int main()
	{
		int counter;
		FILE *ptr_myfile;
		struct rec my_record;

		ptr_myfile=fopen("test.bin","rb");
		if (!ptr_myfile)
		{
			printf("Unable to open file!");
			return 1;
		}
		for ( counter=1; counter <= 10; counter++)
		{
			fread(&my_record,sizeof(struct rec),1,ptr_myfile);
			printf("%d\n",my_record.x);
		}
		fclose(ptr_myfile);
		return 0;
	}

The only two lines that are changed are the two lines in the “for loop”. With the fread we read-in the records (one by one). After we have read the record we print the member x (of that record).

The only thing we need to explain is the fseek option. The function fseek must be declared like this:


     int fseek(FILE * stream, long int offset, int whence);

The fseek function sets the file position indicator for the stream pointed to by the stream. The new position, measured in characters from the beginning of the file, is obtained by adding offset to the position specified by whence. Three macros are declared in stdio.h called: SEEK_SET, SEEK_CUR and SEEK_END.

If the position declared by whence is SEEK_SET, then the position is the beginning of the file.

The SEEK_END can be used if you want to go to the end of the file. (Using negative numbers it is possible to move from the end of the file.)

If whence is SEEK_CUR then the position is set, x bytes, from the current position.

Let’s take a look at an example:


	#include<stdio.h>

	/* Our structure */
	struct rec
	{
		int x,y,z;
	};

	int main()
	{
		int counter;
		FILE *ptr_myfile;
		struct rec my_record;

		ptr_myfile=fopen("test.bin","rb");
		if (!ptr_myfile)
		{
			printf("Unable to open file!");
			return 1;
		}
		for ( counter=9; counter >= 0; counter--)
		{
			fseek(ptr_myfile,sizeof(struct rec)*counter,SEEK_SET);
			fread(&my_record,sizeof(struct rec),1,ptr_myfile);
			printf("%d\n",my_record.x);
		}
		fclose(ptr_myfile);
		return 0;
	}

In this example we are using fseek to seek the last record in the file. This record we read with fread statement and with the printf statement we print member x of the structure my_record. As you can see the “for loop” also changed. The “for loop” will now countdown to zero. This counter is then used in the fseek statement to set the file pointer at the desired record. The result is that we read-in the records in the reverse order.

A last note: if you set the file position indicator to a position in a file and you want the first position in a file then you can use the function rewind to the first position in the file. The function rewind can be used like this:


	#include<stdio.h>

	/* Our structure */
	struct rec
	{
		int x,y,z;
	};

	int main()
	{
		int counter;
		FILE *ptr_myfile;
		struct rec my_record;

		ptr_myfile=fopen("test.bin","rb");
		if (!ptr_myfile)
		{
			printf("Unable to open file!");
			return 1;
		}

		fseek(ptr_myfile, sizeof(struct rec), SEEK_END);
		rewind(ptr_myfile);

		for ( counter=1; counter <= 10; counter++)
		{
			fread(&my_record,sizeof(struct rec),1,ptr_myfile);
			printf("%d\n",my_record.x);
		}
		fclose(ptr_myfile);
		return 0;
	}

With the fseek statement in this example we go to the end of the file. Then we rewind to first position in the file. Then read-in all records and print the value of member x. Without the rewind you will get garbage. (Try it!)

That is all for this tutorial.

This entry was posted in C Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. Tweet This! Tweet This! or use to share this post with others.

There are currently 9 responses to “C Tutorial – Binary File I/O”

Why not let us know what you think by adding your own comment!

  1. pankaj on February 22nd, 2010:

    this is outstanding succint tutorial for file handling . helps a lotttttt.
    thank you.

  2. betagtx260 on March 25th, 2010:

    Hi, i have modified the write section for can write just 1 byte, but it don’t work,

    /* Our structure */
    struct rec
    {
    int mydata;

    };

    int main()
    {

    int counter;
    FILE *ptr_myfile;
    struct rec my_record;

    ptr_myfile=fopen(“test.bin”,”w”);
    if (!ptr_myfile)
    {
    printf(“Unable to open file!”);
    return 1;
    }
    // for ( counter=1; counter < 5; counter++)
    // {
    my_record.mydata= counter;
    // fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);
    fwrite(&my_record, sizeof(struct rec), 1,ptr_myfile);
    // }
    fclose(ptr_myfile);
    return 0;
    }

    in my test.bin i read "01 00 00 00" in my hexadecimal editor
    my question is how can don't write the triple 00 00 00 after i have put my 01 in file?
    because in next while i will get 01 00 00 00 02 00 00 00

    Tanks for your help in advance, and sorry for my english im french !

  3. admin on March 25th, 2010:

    @betagtx260
    If I understand your question correctly you want to see only 1byte in the binary file.
    If this is the case you are using the wrong variable type (int in this case), because an unsigned int can hold all the values between 0 and UINT_MAX inclusive. UINT_MAX must be at least 65535. The int types must contain at least 16 bits to hold the required range of values. But it also can vary per compiler and the platform you are compiling for.

    On compilers for 8 and 16 bit processors (including Intel x86 processors executing in 16 bit mode, such as under MS-DOS), an int is usually 16 bits and has exactly the same representation as a short. On compilers for 32 bit and larger processors (including Intel x86 processors executing in 32 bit mode, such as Win32 or Linux) an int is usually 32 bits long and has exactly the same representation as a long. A int holds 32 bits (thus you see 01 00 00 00 in your hex-editor).

    Try the following example to see the sizeof variable types for your target platform:
    #include<stdio.h>

    int main()
    {
    printf(“%d %d \n”, sizeof(int), sizeof(short int));
    printf(“%d %d \n”, sizeof(signed int), sizeof(unsigned int));
    printf(“%d %d \n”, sizeof(char), sizeof(unsigned char));
    return 0;
    }

    The output will be something like this (on a linux intel machine):
    4 2
    4 4
    1 1

    So if you want to see only one byte in your hex editor, change the program to this:
    #include<stdio.h>

    struct rec
    {
    char mydata;
    };

    int main()
    {
    int counter;
    FILE *ptr_myfile;
    struct rec my_record;

    ptr_myfile=fopen(“test.bin”,”w”);
    if (!ptr_myfile)
    {
    printf(“Unable to open file!”);
    return 1;
    }

    my_record.mydata=1;
    fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);

    fclose(ptr_myfile);
    return 0;
    }

    If you open the file test.bin with the hex-editor you will only see 1byte (01 in this case) if you compile for intel platform (win32 and linux.)
    Or if you want to use int, accept that 4 bytes are written in the binary file (but at least you know now why this is.)

    Hope that this answers your question!

  4. betagtx260 on March 25th, 2010:

    Thanks for your fast reply,
    and i understand now,
    Tanks again ;-)

  5. betagtx260 on April 2nd, 2010:

    Hi, after piratical and try to understanding write and read,
    my write is perfect what i want, but i can not read my bin file, i need some help please,

    this is my write test file work 100%

    int main()
    {
    int i;
    int counter;
    FILE *ptr_myfile;
    struct rec my_record;

    ptr_myfile=fopen(“test.bin”,”wb”);
    if (!ptr_myfile)
    {
    printf(“Unable to open file!”);
    return 1;
    }

    for ( counter=0; counter < 10; counter++)
    {

    my_record.mydata= i;
    fseek ( ptr_myfile , counter , SEEK_SET );
    fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);

    i++;

    }
    fclose(ptr_myfile);
    return 0;
    }

    it generate a .bin file , and in a hexadecimal editor you can read 01 02 03 04 05 06 07 08 etc….

    but i can not read the test.bin file with fread, i will appreciate your help again
    Thanks in advance

  6. admin on April 3rd, 2010:

    @betagtx260 – Below you will find a binary write example and a binary read example. I have tested them and they work, so good luck!
    //Write the test.bin file!!
    #include<stdio.h>

    struct rec
    {
    char mydata;
    };

    int main()
    {
    int i;
    int counter;
    FILE *ptr_myfile;
    struct rec my_record;

    ptr_myfile=fopen(“test.bin”,”wb”);
    if (!ptr_myfile)
    {
    printf(“Unable to open file!”);
    return 1;
    }
    i = 0;

    for ( counter=0; counter < 10; counter++)
    {
    my_record.mydata= i;
    fseek ( ptr_myfile , counter , SEEK_SET );
    fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);
    i++;
    }
    fclose(ptr_myfile);
    return 0;
    }

    //Read the test.bin file!!
    #include<stdio.h>

    struct rec
    {
    char mydata;
    };

    int main()
    {
    int counter;
    FILE *ptr_myfile;
    struct rec my_record;

    ptr_myfile=fopen(“test.bin”,”r”);
    if (!ptr_myfile)
    {
    printf(“Unable to open file!”);
    return 1;
    }
    for ( counter=1; counter <= 10; counter++)
    {
    fread(&my_record,sizeof(struct rec),1,ptr_myfile);
    printf(“%d\n”,my_record.mydata);
    }
    fclose(ptr_myfile);
    return 0;
    }

  7. betagtx260 on April 4th, 2010:

    Hi, Tanks for your help and support,
    my last message with my binary writer test, is perfect for me, because i can write a hex value directly in file , 00 to FF anywhere i want in file, but i cant read it with fread after, i want practice this with a small file i have create because my true application i want manage .iso file,
    and i have no success with fread with iso file.

    Tanks again

  8. selewa on July 29th, 2010:

    Is this the right declaration of a binary file
    Binary files should have b in the mode
    e.g. w+b or wb
    Am I right?

  9. admin on July 29th, 2010:

    @selewa :
    You are right, if you only look at the syntax. But if you open test.bin with text editor, you will see all kinds of ascii values. This is because we write/read records (structs.)
    So there will be now difference between the content of a file written with only “w” or “wb”. But to keep the syntax correct, we have changed the source code examples.
    The modes you can use are as follows:
    r – open for reading
    w – open for writing (file need not exist)
    a – open for appending (file need not exist)
    r+ – open for reading and writing, start at beginning
    w+ – open for reading and writing (overwrite file)
    a+ – open for reading and writing (append if file exists)

    To open a file in binary mode you must add the letter b to the end of the mode string; for example, “wb”.
    For the read and write modes, you can add the b, either after the plus sign – “r+b” – or before – “rb+”.

    Good luck and thx for correcting us!

Leave a Reply: