Fundamental C - Files
Written by Harry Fairhead   
Monday, 20 January 2020
Article Index
Fundamental C - Files
Text Mode
Structs As Records

Text Mode

If you open a file in text mode then it is very like using printf and scanf to send characters to the screen and read characters from the keyboard. In fact the equivalent file functions are fprintf and fscanf.

For example, to write the string “Hello File World” to a file you would use:

FILE *f=fopen("myFile.txt","w");    
fprintf(f,"Hello File World");
fclose(f);

You don’t have to use any particular form of filename, but the extension .txt is suggestive that this is indeed a text file.

Of course, you can reopen the file and read the data back:

f=fopen("myFile.txt","r");
char text[100];
fscanf(f,"%s",text);
fclose(f);
printf("%s",text);

Notice that you can reuse the variable that stores the file pointer. If you try the program you will find that it only prints Hello the reason is that fscanf, like scanf, only reads the input characters until it reaches the first space. |

We have all of the problems we encountered earlier reading data from the keyboard. Of course we do, the keyboard is just another stream of data and the functions that work with it are more or less the same.

You have to be careful not to read too much data and overrun the buffer in exactly the same way. In the case of files on disk or other storage this is usually easier in principle because they are generally written by programs and hence have a fixed format. Even so you have to protect your program from buffer overrun – i.e. you cannot depend on a file format to avoid buffer overrun.

In an earlier chapter we also encountered fputs and fgets as ways of safely reading and writing strings to a file and these are the best functions to use in most cases. The:

fputs(string,fptr);

function will write the characters in a string to the file, but it does not write the final NULL. It returns EOF if there is a problem and a non-negative value otherwise

The function:

fgets(string,length,fptr);

reads characters from the file until it reaches length-1 characters or a newline character. The string returned is always null-terminated.

You can see that using fgets means that you shouldn’t ever overrun a buffer, but to make things work properly you have to arrange to write a newline character to mark the end of the string written to the file.

For example, to write the Hello File World string you would use

FILE *f=fopen("myFile.txt","w");
fprintf(f,"Hello File World\n");
fclose(f);

which explicitly includes a newline character to mark the end of the string.

You could also use:

FILE *f=fopen("myFile.txt","w");    
fputs("Hello File World\n",f);
fclose(f);

To read this back you could use:

f=fopen("myFile.txt","r");
char text[100];
fgets(text,100,f);
fclose(f);
printf("%s",text);

Now when you run the program you will see the entire line “Hello File World” as the fgets reads to the newline character. Notice that the newline character is not included in the returned string which is null-terminated. Using this approach you cannot overrun the buffer by not finding a newline character.

Text formatted file handling is always a matter of making sure that you write something out using separator and end-of-record markers to allow you to read the data back in and parse it to separate the data. There is an argument that working with text files is difficult and best avoided. However, if the data isn’t being generated by you then you might not be able to. The one big advantage of a text file is that it can be read by simple applications such as editors.

Binary mode files are quite different and the way that they work is compared to text mode in the next section.

Binary Files

In many ways binary files are easier to understand and work with. A binary file reads and writes bytes that correspond to the bit patterns stored in C variables. There is no conversion of any sort applied. If you write a 4-byte int out to a binary file then the four bytes are written out exactly as they are stored in memory. The same is true when you read the bytes back in.

If you open a file in binary mode then the only two functions you need to know about are:

fread(ptrToBuffer, size, number, fptr);

and

fwrite(ptrToBuffer,size,number,fptr);

They work in the same sort of way, but one reads and one writes bytes to the binary file. The number parameter gives the number of “variables” each of size bytes that will be transferred to or from the buffer referenced by ptrToBuffer. The buffer can be an array of the appropriate type. Each function returns the number of “variables” written or read which could be smaller than the number specified.

For example, to write three ints out to a file you would use:

int data[3] = {1, 2, 3};
FILE *f = fopen("myFile.bin", "wb");
fwrite(data, 4, 3, f);
fclose(f);

Notice that in this case we can simply pass the array name as it decays to a pointer to the array in this situation. You don’t have to use any particular extension for the filename but .bin is common. Notice that this only works if int really is four bytes in length.

A more portable way to write this is:

fwrite(data, sizeof(int), 3, f);

To read the data back in you would use something like:

f = fopen("myFile.bin", "rb");
int data2[3];
fread(data2, 4, 3, f);
fclose(f);
printf("%d", data2[0]);

Once you get the idea that all that is happening is that the bytes in memory are being written out to disk and then read back in without modification, you should be able to work out the different ways of using this idea.

For example, to write out a single variable you can use:

int myData=42;
FILE *f = fopen("myFile.bin", "wb");
fwrite(&myData, sizeof(int), 1, f);
fclose(f);

and to read it back in:

f = fopen("myFile.bin", "rb");    
fread(&myData, sizeof(int), 1, f);
fclose(f);
printf("%d", myData);

Notice that when you write out a value using binary mode you get exactly the same value when you read it back in. This isn’t necessarily the case if you use text mode, when the value might be converted to a decimal representation before being converted back to binary when read in. Also notice that text mode can use many more bytes to represent the value.



Last Updated ( Monday, 20 January 2020 )