Monday, April 30, 2012

Coding lessons: Writing files in C


In the last lessons I looked at reading files using gets, fgets and fscanf.
to you should be fully aufait on how to read data from files, and how to recognise the end of a file.

Now we'll look at how to write data to files

we mentioned previously that files could be opened in a couple of ways, for reading, writing, or appending.

but that these did not mean exactly that.
reading meant that the file would be opened and the file stream pointer placed at the start of the file in order to start reading
writing meant that the file would be truncated to zero and that the file stream pointer would be placed at the start of the file read for writing
appending mean that the file would be opened and the file stream pointer placed at the end of the file ready for writing

there was also the opportunity to add a plus to these file mode operators and that would mean that the file was opened for reading and writing regardless of whether you said, I want to open this file for reading, or I want to open this file for writing.


Which sounds  bit strange, why specify you want a file mode to be reading, or writing if you then say, I want to open for reading, but writing too, or I want to open for writing, but also reading.

it's more to do with the file pointers and where the file stream points to in the file.

First lets look at the basic functions for writing files, then a few code samples that will help solidify what the file opening modes actually mean.

When reading files we looked at getc first. so it makes sense to look at putc first.

in this example to make sense of the code you must realise that in a computer letters are represented by numbers.

for example A = 65, B =66

or more accurately A = 01000001 , b = 01000010
B is numerically on more than A.

so the loop for (letter = 'A'; letter<= 'Z'; letter++) means go through the alphabet starting at A and going to Z


When we used getc we said character = getc (resource)
putc needs arguments that are, what you want to put there, and the place you want to put it.


#include<stdio.h>
int main()
{
FILE * filepointer;
char letter;
filepointer=fopen("file.txt", "w");

for (letter = 'A'; letter <= 'Z'; letter++ )
{
putc(letter, filepointer);
}
fclose (filepointer);
}


when you run the code above a file is created in the same directory as the exe file, the file is called file.txt and contains the letters A - Z all on one line.

So lets try some examples to show those different modes for opening a file

first lets change the contents of the file add something to the end.

now run the application again.
open the file, it now only contains letters A-Z

That is because the file was opened in write mode.
where the file is truncated (reduced to Zero) and then written

now change the code

#include<stdio.h>
int main()
{
FILE * filepointer;
char letter;
filepointer=fopen("file.txt", "w");

for (letter = 'L'; letter <= 'Z'; letter++ )
{
putc(letter, filepointer);
}
fclose (filepointer);
}


compile and run, and your file now only contains charecters L - Z

so now lets change the lemthod of opening.

#include<stdio.h>
int main()
{
FILE * filepointer;
char letter;
filepointer=fopen("file.txt", "a");

for (letter = 'A'; letter <= 'Z'; letter++ )
{
putc(letter, filepointer);
}
fclose (filepointer);
}


compile and run, the file now has A-L from the last program, and A-Z added after that, each tile you run the program letters A-Z will be added to (end of) the file.


#include<stdio.h>
int main()
{
FILE * filepointer;
char letter;
filepointer=fopen("file.txt", "r");

for (letter = 'A'; letter <= 'Z'; letter++ )
{
putc(letter, filepointer);
}
fclose (filepointer);
}


now try compiling and running that, (it will compile and will run).
run as many times as you like, notice how nothing is added to the file, that's because the file is only opened for reading.

#include<stdio.h>
int main()
{
FILE * filepointer;
char letter;
filepointer=fopen("file.txt", "r+");

for (letter = 'A'; letter <= 'Z'; letter++ )
{
putc(letter, filepointer);
}
fclose (filepointer);
}


Compile and run this, the file is now opened for reading and writing.

run this a few times.
see what happens, -the file doesn't grown, is just continues to contain the letters A-Z

now leave the file alone and compile and run this code

#include<stdio.h>
int main()
{
FILE * filepointer;
char letter;
filepointer=fopen("file.txt", "r+");

for (letter = 'L'; letter <= 'Z'; letter++ )
{
putc(letter, filepointer);
}
fclose (filepointer);
}


now run this.

the file called file.txt did contain the following text
ABCDEFGHIJKLMNOPQRSTUVWXYZ

now it contains
LMNOPQRSTUVWXYZPQRSTUVWXYZ

If you go all the way to the top of the tutorial you see I talked about where the file pointer goes

When you open a file for Writing, the file is truncated (reduced to zero) and the file pointer is put at the start.

We see this because anything that we put in the file is lost and over written, not matter how big of how small only what the program says ends up in the file.

When you open a file for appending, the file is opened and the file stream pointer placed at the end of the file, this means that the characters that we're adding get put at the end of the file. so the file grows.

When we open a file for reading the file pointer is placed at the start of the file.
adding the plus doesn't change the modes main property which is where the file stream is in the file (at the beginning) so you see how additions to the file overwrite text that is in the file.


More ways of writing.
There are (of course) more ways to write to a file than simply putting individual characters into a file stream.

We can also put strings into files using fputs
fputs only has two arguments, like putc it just needs to know what you want to write, and where you want to write it.

#include<stdio.h>
int main ()
{
FILE * filepointer;
char string[] = "the quick brown fox jumps over the lazy dog";
filepointer = fopen("file.txt","a");
fputs (string,filepointer);
fclose (filepointer);
}



And finally, in the same way that we use printf to write to the console, we can use fprintf to write to a file.

#include<stdio.h>
int main ()
{
FILE * filepointer;
char string[] = "the quick brown fox jumps over the lazy dog";
int number = 13;
filepointer = fopen("file.txt","a");
fprintf(filepointer, "%s, well actually is was %d lazy dogs", string, number);
fclose (filepointer);
}


I added in some variables, fprintf works exactly the same way that printf does except that you need the first argument to be where you want to put the stuff, then what you want to put there.

in fact it works so much like printf that you can tell it this:

fprintf(stdout, "%s, well actually is was %d lazy dogs", string, number);

stdout is the console, you're telling it to write to the console as if it were a file.

No comments: