Inverting the Binary file, File Handling in C
Jan 1, 2018The file handling is one of the most crucial part of the programming, It plays very important role in software development. In this topic i am demonstrating the feature of the file handling using C programming. Basically there are two types of files in which data can be stored in two ways either in characters encoded in their ASCII set or in binary format they are.
I) Text Files
A text file contains only text information like alphabets, digits and special symbols. The ASCII codes of these files are stored in these files. It uses only 7 bits allowing 8 bit to be zero.
II)Binary Files
A binary file is a file that uses all 8 bits of a byte for storing the information. It is the form which can be interpreted and understood by the computer.
The only difference between the text file and the binary file is that the data contained in the text file is understood by the wordprocessor while binary data can't be recoznized by the wordprocessor.
Although the text files and binary files are two different things, basic operation on file handling process is same. The file operation needs the following basic file operations.
- opening a file
- reading data from a file
- writing data into a file
- closing a file
Since this topic demonstrates the concept and use of the file handling, I am just explaining the file handling for binary files in C programming. A file represents the sequence of bytes, regardless of it being text files or binary files. C programming language provides access on high level functions as well as low level (OS level calls) to handle call on your storage devices.
1) Opening a file
You can use the fopen( ) function to create a new file or to open an existing file. This call will initialize an object of the type FILE, which contains all the information necessary to control the stream. The prototype of this function call is as follows −
FILE *fopen( const char * filename, const char * mode );
Here, filename is a string literal, which you will use to name your file, and access mode can have one of the following values −
S.N. | Mode & Description |
---|---|
1 |
r Opens an existing text file for reading purpose. rb (for binary files) |
2 |
w Opens a text file for writing. If it does not exist, then a new file is created. Here your program will start writing content from the beginning of the file. wb (for binary) |
3 |
a Opens a text file for writing in appending mode. If it does not exist, then a new file is created. Here your program will start appending content in the existing file content. ab (for binary) |
4 |
r+ Opens a text file for both reading and writing. a+b (binary) |
5 |
w+ Opens a text file for both reading and writing. It first truncates the file to zero length if it exists, otherwise creates a file if it does not exist. w+b (binary) |
6 |
a+ Opens a text file for both reading and writing. It creates the file if it does not exist. The reading will start from the beginning but writing can only be appended. a+b (binary) |
2) Reading data from a file(binary file)
Since we are dealing only with binary type file, Only binary file related I/O functions will be discussed. Syntax for reading is
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
ptr - This is pointer to a block of memory with minimum size of size_of_elements * number_of_elements BYTES.
size_of_elements - This is the size of each elements to be read.
number_of_elements - This is the number of elements each one with a size of size_of_elements BYTES.
a_file - This is the pointer to a FILE Object that specifies the input stream.
The total number of elements successfully read are returned as size_t object, which is an integral data type. If this number differes from the number_of_elements parameter, then either error had occured or end of file is reached.
3) Writing data to a file(binary file)
This is accomplished using fwrite() function it's prototype is..
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
ptr - This is pointer to an array of elements to be written.
size_of_elements - This is the size in BYTES of each elements to be written.
number_of_elements - This is the number of elements each one with a size of size_of_elements BYTES.
a_file - This is the pointer to a FILE Object that specifies the output stream.
The total number of elements successfully written are returned as size_t object, which is an integral data type. If this number differes from the number_of_elements parameter, it will show an error.
4) Closing a file
The C library function int fclose(FILE *stream) closes the stream. All buffers are flushed. The declaration for fclose() function is
int fclose(FILE *stream);
stream - This is the pointer to a file to be closed.
This function returns 0 if the stream is successfully closed. On failure EOF is returned.
Now, for easier and more manageable code, I prefer to write code with functions. For the tasks given the problem is divided and each task is fullfilled by the function. The main logic behind the inversion of the bit patterns of the file is that, the individual byte read from the file is XORed with byte according as requirement of bit inversion. For example if we want to invert all the bit patterns of the binary file we have to XOR the read byte with 0xFF and if alternately then with 0xAA. since any bit XORed with 1 results the inverted bit and if we XORed it with 0 the bit will be same.
##FUNCTION DECLARATION
//function declaration FILE *openFile(char *file_name, char *mode); short int closeFile(FILE *file_pointer); void convertFile(FILE *source_pointer, FILE *destination_pointer, unsigned char invert_pattern);
##FUNCTION DEFINATION
//function defination FILE *openFile(char *file_name, char *mode){ return fopen(file_name,mode); }
short int closeFile(FILE *file_pointer){ int stat = fclose(file_pointer); if(stat == 0){ return 1; }else{ return 0; } }
void convertFile(FILE *source_pointer, FILE *destination_pointer, unsigned char invert_pattern){ unsigned char one_byte; while(!feof(source_pointer)){ fread(&one_byte,1,1,source_pointer); one_byte ^= invert_pattern; fwrite(&one_byte,1,1,destination_pointer); } }
FILE *openFile(char *file_name, char *mode);
This function accepts two arguments as from above prototype strings using pointer, one for file name with path and another for mode of opening. It returns the pointer of FILE type object on successfull opening of file and returns NULL if it fails.
short int closeFile(FILE *file_pointer);
This function accepts one arguments of type FILE object pointer. It returns 1 on successfull closing of file and returns 0 if it fails.
void convertFile(FILE *source_pointer, FILE *destination_pointer, unsigned char invert_pattern);
This function accepts three arguments source pointer, destination pointer, and inversion bit pattern. It returns nothing.
The main function
For simplicity I want to run the program in command line. Since it will be easier for passing file names while running program from terminal. The feature called command line arguments faciliates us that. For example if we want to take operation on file name called file.mp4 then we can dynamically pass during program running. I am compiling and running the program in ubuntu terminal. Its like ./runnable_file argument1 agument2............ where ./runnable_file is file that is ready to run and others are arguments. Its prototype is
int main(int argc, char *argv[]);
Here the argc is number of arguments and the argv is the array of string(pointer to string). By default the argc is 1 since compiler counts program name as arguments.
The main function is as shown.
int main(int argc, char *argv[]) { if(argc != 3){ printf("Requires three arguments"); exit(0); } char *source_file = argv[1]; char *destination_file = argv[2]; unsigned char invert_pattern = 0xFF; FILE *source_pointer = openFile(source_file,"rb"),*destination_pointer = openFile(destination_file,"wb"); if(source_pointer == NULL || destination_pointer == NULL) { printf("error on opening file"); return 0; } convertFile(source_pointer,destination_pointer,invert_pattern); if(closeFile(source_pointer) == 1){ printf("source file closed\n"); }else{ printf("source file closing failed\n"); } if(closeFile(destination_pointer) == 1){ printf("destination file closed\n"); }else{ printf("destination file closing failed\n"); } if(remove(source_file) == 0){ printf("file removed\n"); } return 0; }
finally, summing up....
#include <stdio.h> #include <stdlib.h> //function declaration FILE *openFile(char *file_name, char *mode); short int closeFile(FILE *file_pointer); void convertFile(FILE *source_pointer, FILE *destination_pointer, unsigned char invert_pattern); int main(int argc, char *argv[]) { if(argc != 3){ printf("Requires three arguments"); exit(0); } char *source_file = argv[1]; char *destination_file = argv[2]; unsigned char invert_pattern = 0xFF; FILE *source_pointer = openFile(source_file,"rb"),*destination_pointer = openFile(destination_file,"wb"); if(source_pointer == NULL || destination_pointer == NULL) { printf("error on opening file"); return 0; } convertFile(source_pointer,destination_pointer,invert_pattern); if(closeFile(source_pointer) == 1){ printf("source file closed\n"); }else{ printf("source file closing failed\n"); } if(closeFile(destination_pointer) == 1){ printf("destination file closed\n"); }else{ printf("destination file closing failed\n"); } if(remove(source_file) == 0){ printf("file removed\n"); } return 0; } //function defination FILE *openFile(char *file_name, char *mode){ return fopen(file_name,mode); } short int closeFile(FILE *file_pointer){ int stat = fclose(file_pointer); if(stat == 0){ return 1; }else{ return 0; } } void convertFile(FILE *source_pointer, FILE *destination_pointer, unsigned char invert_pattern){ unsigned char one_byte; while(!feof(source_pointer)){ fread(&one_byte,1,1,source_pointer); one_byte ^= invert_pattern; fwrite(&one_byte,1,1,destination_pointer); } }