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 is outstanding succint tutorial for file handling . helps a lotttttt.
thank you.
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 !
@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!
Thanks for your fast reply,
and i understand now,
Tanks again 😉
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
@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;
}
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
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?
@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!
Hi,
Is there a possibility to deal with data packing of the compiler in the structure, because due to this structure members are not necessarily continuous in the memory.
For example, the size of a structure with a uint_8 and uint_32 variable in there is usually 8 bytes instead of 5 due to compiler data packing.
Now, if you want to read the 5 bytes from your binary file using:
fread(&my_record,sizeof(struct rec),1,ptr_myfile);
you will read the wrong bytes in the fields (the uint32 variable will only have one byte).
Is there any method to prevent this??
Thanks!
Martin.
I’ve seen people read 1 byte at a time, then if you need it to be one number just multiply it by it corresponding position…
first number n*10000
+ second number n*1000
+ third number n*100
+ forth number n*10
+ fifth number n..
I’m not a professional so please research for better ways.
In your last example you do the following…
fseek(ptr_myfile, sizeof(struct rec), SEEK_END);
rewind(ptr_myfile);
And mention that you get garbage without the rewind. If you seek to the end of file and then offset beyond the end of the file, you will be reading garbage, you need a negative offset.
These 2 lines are pointless in your example. Or am I mistaken?
@radix: the goal of that example is to show how to use of the rewind() function. That’s why the end of the file is searched (otherwise there is nothing to rewind from) and then rewind() is called to go to first position of the file.
You will get garbage if rewind isn’t called because the for loop will try to read records beyond the end of the file, because there is no check performed to check if the end of the file has been reached.
So again it’s just to show the use of the rewind() function: nothing more, nothing less. The search for the end of the file is only done, so we that we can rewind.
I want to dump some memory into a file, a complex structure which contains pointers to list etc, and again want to set the same memory from this file.
Is it possible to do with fwrite & fread functions
I want to store a character array data (89 bytes) to a binary file. Please send the fwrite function code for this. Is it possible to store current PC time to same binary file?
Thanks,
Sandeep
the first example in the web page only writes to variable x? how to write and read using variable y and z?
@mohammed – It’s very easy to use variables y and z in the first write and read examples. You just have to add some additional lines. The examples now only uses the variable x to keep the examples smaller. To use all three (x,y,z) variables add the following lines to the examples:
Write for loop:
for ( counter=1; counter <= 10; counter++) {
my_record.x= counter;
my_record.y= counter;
my_record.z= counter;
fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);
}
The read example:
for ( counter=1; counter <= 10; counter++) { fread(&my_record,sizeof(struct rec),1,ptr_myfile); printf("%d\n",my_record.x); printf("%d\n",my_record.y); printf("%d\n",my_record.z); } As you can see we only have to fill the other two variables (y and z) as we did with x variable. Then we can read them as we did x in the read example. Hope this helps!
tnx for some example of the program tnx a lot….more power
This was an extremely helpful tutorial. Thank you so much.
I understand that fseek() offsets the pointer by characters. Is there anyway I can offset the pointer by ‘n’ number of lines? I’m trying to write/overwrite a string to a specific line in my text file. I tried
fprintf(myfile+3, “www.codingunit.com”);
but it does not offset my pointer to line 3 in my textfile. Please enlighten me with your wisdom, great one. 🙂
Thanks again!
Alan
[…] C Tutorial – Binary File I/O | CodingUnit Programming Tutorials. Rate this: Share this:TwitterFacebookStumbleUponPrintEmailLinkedInLike this:LikeBe the first to […]
very nicely explained .. thnXX
Very useful.
Hey everybody!
Thanks a lot for the kind help. It really helped me to my aim what I was finding.
Thanks again… Have happy programming…!
Thanks for writing this! exactly what I needed to know for my project
Amazing tutorial, very well explained. Thanks 😀
it is awsome..it helps me a lot to understand binary files..Can you add another program of telling how to add and delete records at particular positions..?
Hello I am trying to read satellite CEOS format file which contacined all type of data like integer ascii,binary.
I know structure of binary file. I am reading file according to structure but not able to display data. Is it require after reading data structure-wise to conver binary to decimal format? or can I use “cout” to display binary data directly.
please tell me how can can i change the binary number into radix.
using string.
like:
binary number of 64 will be 1000000
(binary)1000000 = 64 (radix)
Awesome tutorials……very helpful……Thanks a lottttt for this…!!!
I want to know how .bmp images are displayed using the C programming language…. …….
Amazing Tutorial ,thanks
Simply wonderful tutorial.
Thank you!