Files

In the past, you’ve been limited to input and output to and from the console window. No longer! File IO allows you to do the same with files. For example, you can input data from a text file, and output other data to another file! It’s not very complicated, so this should be a pretty short topic.

File Output

File output is a bit simpler than file input—it’s essentially the same as what you’ve been doing with "cout," except with files. First, if you are going to do file input or output, you need to include the "fstream" header. It's just like including the "iostream" header.

When you want to output to a file, you declare a variable of type "ofstream." This will serve as your data stream for file output.

ofstream fout;

To open a file for output, you can call the method "open" with the name of your file as the parameter. Note that the file name must be a c-style string, meaning either a character array or a string literal. If the file you specify already exists in the same directory as your executable, it will overwrite the file, and if not, your program will create the file for you.

You will most often create ".txt" files, as your operating system will automatically recognize it as a text file. However, you can use any filename and extension that you want, and they will all work just the same.

fout.open(“outfile.txt”);

Now, you can use your "fout" variable in the exact same way you would use "cout." Your data will be written to the file as you would expect.

fout << “Start of file:” << endl;
fout << data << “ “ << moreData << endl << endl;

That’s pretty much all there is to basic file output—just remember the process works in exactly the same way as output to the console.

File Input

File input is a bit more complicated, as you have to deal with the fact that you may not get the data you expect from the file. Like file output, it works in much the same way as console IO. Once you have included the "fstream" header, you can declare a file input stream with the type "ifstream."

ifstream fin;

To open a file for input, simply call the "open" method with a c-style string of your file name. However, if the file does not exist, your program will not create the file—in fact, it won’t do anything at all. If your program can’t find the specified file, your "fin" variable will be marked as invalid. To test if your file stream is valid, you can call the method "good." You can use this method to test if you received a legitimate file.

fin.open(“infile.txt”);

if(fin.good()) {
	// Do stuff
} else {
	cout << “File was invalid!” << endl;
}

Once you have successfully opened your input file, you can proceed how you would expect. File input works in the same way as input from the console, except you don't need direct user input, as the data should already be laid out in the file.

Remember that when you input using the extraction operator, if your program sees whitespace (spaces, tabs, or newlines), it will automatically skip over them until it comes to a valid piece of data. When you input a value using the extraction operator, your place in the file will move forward, past whitespace, and then past the data. Finally, when creating a data file, always add a blank line after the end of your data, else your program may see the last input from the file as invalid when it should not.

fin >> someData >> moreData;

If the example file is simply "100 234," the first input to "someData" would move your position forward in the file, so your program would now only see " 234." Note that there is still a space in front of the 234. Then, when the second input is performed, your program will skip over any white space in the file (spaces, tabs, newlines), until it comes to the next piece of data ("234") and inputs it.

Finally, you may be wondering what happens when your file does not have valid data, or if the file ends before you’re done inputting from it. Well, this works in the same way as if you try to open a bad file—if your input stream fails for any reason, it will be marked as invalid. Again, you can test if the stream is valid by using the "good" method. After you input data from a file, you should usually check if the input succeeded. If you don't, you don’t know if you have good data or not.

for(int i = 0; i < 10; i++) {
	fin >> array[i];
}

if(!fin.good())
	cout << “Data did not input correctly!” << endl;

Three Methods of File Input

Using file input in the exact same way as console input is useful to input single values and the like, but to input larger quantities of data there are three more effective methods.

First, there is the simplest. It requires that you know how much data you want to input before you actually run your program. The method is simply to loop the number of values you want to input, and input one each time.

for(int i = 0; i < 10; i++) {
	fin >> array[i];
}

This inputs 10 values from the "fin" file stream to an array.

Second, you can specify the amount of data you want to input within the file itself. Essentially, you put the number of values before the actual data, and loop that many times to input the actual data.

File: "5   9 34 23 1 8"

fin >> numValues;

for(int i = 0; i < numValues; i++) {
	fin >> array[i];
}

This will first see that there are 5 values in the file, then loop 5 times to input them.

Finally, the third type of input is simply looping until you reach the end of the file. This is arguably the easiest way to input data, but it can only be used if you want to input everything in a file, until the end. To implement this type of input, you simply input values until reaching the end of the file, where your input stream will be marked as invalid. Hence, you can do something like this...

do {
	fin >> dummyData;
} while(fin.good());

This code will input a value from the file, and if the file is still valid, it will input another value, and so on.

You have to be careful when using this type of file input. The example uses a do...while loop rather than simply a while loop, because you need to input the value before checking if the stream is still valid. Why? Well, if you test the validity of the file before you input the value, when you get to the last legitimate value, you will input another value before the program realized you’ve reached the end of the file. This is another one of those pesky off-by-one errors, except this time it will give you an extra, garbage value.

IO Functions

These are a few functions that can be called from your file variables or from "cin." These will be very useful in formatting and checking your input.

getline()

This first function is not actually called as a method from “cin” or a file stream variable, but simply called on its own. As the name suggests, it is used to input an entire line of input, rather than just one word or value. For example, if your input stream contains "first last," and you use the extraction operator, you will only receive the word "first." However, if you use the getline() function, you can input the entire line ("first last") as one string. getline() works with C++ string data types, which we will learn about later.

getline() takes three parameters: the input stream you want to take from (e.g. "cin" or "fin"), the string variable you want to input into, and the delimiting character. By default, the delimiting character is the newline character, which means the function will input text until the end of the line. However, you can specify a different character.

getline(cin,stringVar);

Inputs a line from the console.

getline(fin,stringVar,’:’);

Inputs text from a file until it gets to a colon.

.getline()

.getline() is almost exactly the same as getline(), except it is used with c-style strings, and it is called as a method. It also takes slightly different parameters: the character array, or c-string, the maximum characters to input if the delimiting character is not reached, and again an optional delimiting character.

cin.getline(charArray,1000);

Inputs text from the console until it gets to the end of the line or inputs 1000 characters.

fin.getline(charArray,1000,’:’);

Inputs text from a file until it gets to a colon or inputs 1000 characters.

.ignore()

Ignore is a very simple but very useful function: it is used to simply skip data from stream if it is irrelevant. For example, if you had a file containing “Data: 1 2 3 4,” you can’t just start input at the beginning, as the word "Data" is in the way. With .ignore(), you can skip the label and get straight to the data. .ignore() is called from your file variable or "cin," and it takes two parameters: the maximum number of characters to ignore, and the delimiting character. Know that ignore will throw away the data up to and including the delimiting character. Hence, you would want to ignore until a colon in the above example.

cin.ignore(1000,’\n’);

Ignores the console input until the end of the line, or after 1000 characters.

fin.ignore(1000,’:’);

Ignores the data in the file until it reaches a colon, or has ignored 1000 characters.

.get()

.peek()

Get and peek are very simple functions: they return the next character in the input stream, but do not ignore white space like the extraction operator. This means that if the program is at " data" in the file, .get() will give you a space, whereas the extraction operator would ignore the space and give you "data."

The difference between .get() and .peek() is very simple—.get() will remove the character from the input stream when it gives it to you, whereas .peek() will return the character without removing it from the stream. Both are called as methods from "cin" or your file variable, and do not take any parameters.

charTest = cin.get();

Gives you the next character from the console input.

peekChar = fin.peek();

Gives you the next character in the file without removing it from the stream.

Programming Exercises

  1. Write a program to count the number of lines and the number of characters in a text file.
  2. Write a program to input a specified number of integer values from a file into an array, sort the array from lowest to highest, and output the array to the console.
  3. Write a program that allows the user to write input to a text file line by line, until they enter "quit."