Table of Contents

Overview:

  • Terms to know: Input file stream, output file stream, stream operator
  • Concepts:
    • To use file I/O you need to have #include <fstream>
    • How to save files and load and parse them.
  • New code:
    • Declare an Input File variable: ifstream VARIABLE;
    • Declare an Output File variable: ofstream VARIABLE;
    • Open a file (either type of stream): VARIABLE.open( "filename.txt" );
    • To check if there's an error opening the file:

      ifstream infile( "filename.txt" );
      if ( infile.fail() )
      {
          cout << "Error! Could not find file!" << endl;
          return 1;
      }
      
    • Read a word from an input file infile to a variable: infile >> VARIABLE;
    • Read a line of text from an input file infile to a variable:: getline( infile, VARIABLE );
    • Write a string literal to an output file outfile: outfile << "Hello!";
    • Write a variable value to an output file outfile: outfile << VARIABLE;
    • Write a newline into the output file outfile: outfile << endl;=
    • And you can chain them together with <<.

1. Output streams

fileio.png

Saving data from our program and out to an external file is an important part of software. While we'll mostly be working with very simple data types like .txt, .csv, or maybe .html, tons of software everywhere extracts its data into all sorts of formats.

Saving out data can also be useful because the program can load that data in later on, so that each time you run the program all the data and changes made are saved.

In C++ we've been using cout to stream information to the console window in our programs. Using cout requires including the iostream library.

cout << "Hello, " << location << "!" << endl;

Writing out to a text file works in a very similar way. We will need to include the fstream library in order to get access to the ofstream (output-file-stream) object. Streaming out to a file works in the same way as with cout, except that we need to declare a ofstream variable and use it t open a text file.

#include <iostream>             // Console streams
#include <fstream>              // File streams
using namespace std;

int main()
{
  // Console output
  cout << "Hello, world!" << endl;

  // File output
  ofstream outputFile( "file.txt" );
  outputFile << "Hello, world!" << endl;
  outputFile.close();
}

You can use the output stream operator << to continue chaining together different items - endl, string literals in double quotes, variable values, etc. just like with your cout statements.

Once the file is closed, you will see the file on your computer, usually the same directory as your .cpp files.

Review 1. We have the variable hour, how would we output it to the console screen?

  • ○ cout << hour;
  • ○ cout >> hour;
  • ○ getline( cout, hour );

Review 2. What are some types of outputs a program might generate?

  • □ A banana
  • □ A spreadsheet of all the inventory a business has in stock
  • □ A text file log of all chat history between two people.

2. Writing output to files

To write information to the screen first we need to include the file stream library:

#include <fstream>

Then, we declare a variable of type ofstream (output-file-stream). ofstream is the data type, and you can give it whatever variable name:

ofstream outputFile;

Sometimes, your program might read multiple files at once, so then you'd declare more than 1 ofstream variable. But for here, we're just working with the one.

We can then open a file name that we will be writing out to:

outputFile.open( "save.txt" );

Now we can output text to our file in the same way we use cout, except replacing cout with the outputFile variable…

outputFile << "Name: " << name << endl;

If you want to close the file manually, use the .close() function:

outputFile.close();

Otherwise, the ofstream object will close automatically when the program closes or when the function it's declared within exits.

Review 3. Match the lines of code with the descriptions of what they do.

CODE SNIPPETS:

  • a. ofstream output
  • b. output.open( "save.txt" );
  • c. output << "Hello World!";
  • d. output.close();

DESCRIPTIONS: These are out of order, mark which code snippet it describes.

○ a / ○ b / ○ c / ○ d Closes the file currently opened in the output file stream.
○ a / ○ b / ○ c / ○ d Declares an output file stream variable.
○ a / ○ b / ○ c / ○ d Writes text out to the file via the output file stream variable.
○ a / ○ b / ○ c / ○ d Opens a text file to be accessible via the output file stream variable.

The path of the output file

textfile.png

Figure 1: A folder view of a directory where a text file is located.

When you've built a program with g++ and are running it as ./program.out or ./program.exe, the path of that exe file is the working directory. This is the default directory where text files will be saved, and the default directory it will look at to try to open files to load.

You can adjust the path using ../ to go back/up one folder or, if you have a subfolder like a "data" directory, you can use the folder's name FOLDERNAME/file.txt as a path.

textfileB.png

Figure 2: A plaintext editor open showing the contents of restaurants.txt, which contains restaurant names, addresses, and prices.

You can open the text file output with a text editor like notepad or a code editor like VS Code. It's just plaintext!

Review 4. What is the default read/write path for fstream objects?

  • ○ C:\
  • ○ My Documents
  • ○ Same location as the .exe/.out file

Outputting different file types

Many file formats are just plain text files if you open them in Notepad. You can save your program's output to more than just .txt files as well - you could use .csv (comma separated value) files, or .html files, or other file types as well.

Just name your file a .csv or .html file when using the open function:

output.open( "data.html" );

And then output text that is formatted as the correct file type:

output << "<h1>Q1 Data</h1>" << endl;
output << "<p>This year we found that <strong>potatoes</strong>" << endl;
output << "solid well, outselling tomatoes.</p>" << endl;

Any file type that is a plaintext file can be built as well - .html files, .csv files, heck, even .cpp files. However, generally if you wanted to write a program to output a different file type, you'd use a library to properly convert the data.

Example: Outputting HTML data:

#include <fstream>
using namespace std;

int main()
{
  ofstream outputFile( "page.html" );
  outputFile << "<body>" << endl;
  outputFile << "<h1>This is a webpage</h1>" << endl;
  outputFile << "<p>Hello, world!</p>" << endl;
  outputFile << "</body>" << endl;
  outputFile.close();
}

Example: Outputting CSV data:

#include <fstream>
using namespace std;

int main()
{
  ofstream outputFile( "spreadsheet.csv" );
  outputFile << "COLUMN1,COLUMN2,COLUMN3" << endl;
  outputFile << "cell1,cell2,cell3" << endl; // row 1
  outputFile << "cell1,cell2,cell3" << endl; // row 2
  outputFile << "cell1,cell2,cell3" << endl; // row 3
  outputFile.close();
}

Review 5. A .csv file is a spreadsheet-like format with rows, columns, and cells of data. What types of data might be good to store as a .csv file, and what would be better as a simple .txt file?

○ txt / ○ csv A course with its name, search code, and credit hours.
○ txt / ○ csv A game character's level, experience, and amount of gold.
○ txt / ○ csv A list of books with their titles, author names, and isbn.
○ txt / ○ csv A receipt for purchasing a product, including tax and final total price

3. Reading documentation

coding-strategy.png

Documentation is an important part of software development. People who write code that's used by others need to provide documentation so that others can know how to use the functionality without having to read the source code.

The C++ ofstream library docs are here:

https://www.cplusplus.com/reference/fstream/ofstream/

Under the "Public member functions" header is a list of functions that ofstream provides, and clicking on a function will give you some example code and more information.

Review 6. The ofstream::open documentation page has an example of the function's form, which looks like this:

void open (const char* filename,
    ios_base::openmode mode = ios_base::out);

This shows us what inputs the function can take. The filename is the filename we pass to it (e.g., myFile.open( "todo.txt" ); ), and there is an optional mode argument.

What is the data type of the filename argument?

  • ○ const char*
  • ○ float
  • ○ std::string

Review 7. In the ofstream::open documentation, the first paragraph of text describes what this function does. What does it do?

  • ○ Closes the file currently associated with the object, disassociating it from the stream.
  • ○ Opens the file identified by argument filename, associating it with the stream object, so that input/output operations are performed on its content. Argument mode specifies the opening mode.
  • ○ Returns whether the stream is currently associated to a file.

Review 8. In the ios::fail documentation, under Return Value, it describes the possible results of calling this function. What might this function return?

  • ○ a '+' or '-' character
  • ○ a true or false boolean value
  • ○ a negative or positive integer

4. Input streams

fileinput.png

We can use the ofstream library to write text and data out to text files. In the same family of tools, the ifstream library ("input file stream") allows us to read in files for use in our programs.

We could save/load save data files, such as in a video game, so you don't lose your process. You could also load in a document to "process" in some way.

Writing code to read in text is a little harder than just writing something out, because we have to tell our program how to read. Ifstream will bring in words or lines of text for us, but we have to tell our program how to make sense of what it's loaded in. This process is known as parsing.

File input streams work just line console input streams. You will need to create a ifstream (input-file-stream) object and open a file, and then you can read in the contents of that file. Files to be read should generally be placed in the same path as your .cpp file, though the working directory on your system may vary.

Example:

#include <fstream>              // File streams
#include <string>               // Strings
using namespace std;

int main()
{
  string data1, data2;

  // File input
  ifstream inputFile( "file.txt" );
  inputFile >> data1;             // Read one word
  inputFile.ignore();             // Clear buffer
  getline( inputFile, data2 );    // Read one line
  inputFile.close();
}

Just like with using cin, you can use the input stream operator (>>) and the getline() function with the file streams to get text. You will also need one or more variable to store the text read in.

Review 9. What are some examples of input files a program might read? (Multiple selection)

  • □ A banana
  • □ A configuration file for program options
  • □ Family ancestry data
  • □ The text of an ebook

Reading input

We will use the same library to get access to both ofstream and ifstream. Remember "File Stream" is what "fstream" stands for.

#include <fstream>

Remember that ofstream was the data type of the variable we'd create to open a text file and write data out. For input, we use ifstream, but we still can open a file in the same way:

ifstream inputFile;
inputFile.open( "save.txt" );

We can read contents from our input file stream similarly to how we would work with cin for the keyboard input. Reading in one word or piece of data at a time will use the input stream operator >>:

// Read from text file, save to playerExperience variable.
inputFile >> playerExperience;

And reading a whole line of text at a time will use getline:

getline( inputFile, playerName );

We still need to use the ignore() function when moving from a >> statement to a getline statement:

inputFile >> playerHp;
inputFile.ignore();
getline( inputFile, playerName );

And, we can close the file manually if we'd like:

inputFile.close();

The file itself is read from the left-to-right, top-to-bottom, similar to how you might think of a typewriter working. If we use >>, it will read the left word to the right word, and once it hits the end of a line it will return all the way to the left but one line down. If we use getline, it will start at the top line and move down one line at a time as it reads.

Review 10. Let's say we saved a "save game" file in this order:

1. Player name
2. Player's experience points
3. Player's gold amount

What order do we load in the data from the file?

  • ○ Gold then Experience then Name
  • ○ Name then Experience then Gold

Review 11. Match the lines of code with the descriptions of what they do.

CODE SNIPPETS:

  • a. ifstream input
  • b. input.open( "save.txt" );
  • c. getline( input, var2 );
  • d. input >> var1;

DESCRIPTIONS: These are out of order, mark which code snippet it describes.

○ a / ○ b / ○ c / ○ d Read a line of text from the input file into a variable.
○ a / ○ b / ○ c / ○ d Declares an inputfile stream variable.
○ a / ○ b / ○ c / ○ d Reads a word of text from the input file into a variable.
○ a / ○ b / ○ c / ○ d Opens a text file to be accessible via the input file stream variable.

What if the file isn't found?

When we're saving an file with ofstream we don't really have to worry about if the file already exists or not - if it doesn't exist, a new one will be created.

For reading a file with ifstream, however, if no file exists to read, then what? Well, we should check to see if opening the file failed, and if it did, perhaps we use some default values instead, or give an error and exit the program.

To check if the open process failed, we use an if statement:

ifstream input;
input.open( "userdata.txt" );
if ( input.fail() )
{
  cout << "ERROR: Could not find file!" << endl;
  return 2;
}

Review 12. When opening an (○ ifstream / ○ ofstream) file

for (○ loading / ○ saving) we should check to see if the open was successful via the fail() function.

Reading an entire file

Reading chunks of data:
Let's say you have a file full of data to read in. For this example, the file will be a list of numbers that we want to add together. The file might look something like….

File: Data.txt

9 15 16 0 10 13 5 16 1 9 2 17 3 3 8

In our program, we want to read all the numbers, but to do this, we need to use a loop and read in one number at a time. We can keep a running total variable to keep adding data to the sum as we go. We can use a loop to continue reading while it is successful, using this as the condition: input >> readNumber. This will stop the loop once there's nothing else to read, and it updates the readNumber variable with the input each cycle.

Example:

ifstream input( "data.txt" );

int sum = 0;    // Sum variable
int readNumber; // Buffer to store what we read in

// Keep reading while it's possible
while ( input >> readNumber )
  {
    sum += readNumber;  // Add on to the sum

    // Output what we did
    cout << "Read number " << readNumber
         << ",\t sum is now " << sum << endl;
  }

cout << "FINAL SUM: " << sum << endl;

File output:

Read number 9,   sum is now 9
Read number 15,  sum is now 24
(... etc ...)
Read number 3,   sum is now 119
Read number 8,   sum is now 127
FINAL SUM: 127

Reading lines of data:

In other cases, maybe you're reading in text data from a file and want to read in a full line at a time. We can use a while loop with the getline() function as well to make sure we read each line of a text file:

Example:

ifstream input( "story.txt" );

string line;

while ( getline( input, line ) )
{
  cout << line << endl;
}

File output:

CHAPTER I.
Down the Rabbit-Hole

Alice was beginning to get very tired of sitting by her
sister on the bank, and of having nothing to do: once or
twice she had peeped into the book her sister was
reading, but it had no pictures or conversations in it,
"and what is the use of a book," thought Alice "without
pictures or conversations?"

Parsing plaintext files

There are different ways you can design a text file's save format so that you can more easily read it in later on. Let's go over some common techniques. You might also want to take note of these for use in our class projects.

A plaintext file is a file that just contains text, which can be opened in a program like notepad.

5. Saving and loading data

parse1.png

Parsing files

Reading in data from a file is one thing, but making sense of what was read in is another. Are you storing saved data from the last session of the program? Are you trying to parse data to crunch? How do you read that data in logically?

First, if your program is going to be saving output that will need to be read in and made sense of later on, how do you organize the data that's output? It's up to you to make sure to structure the output save data in a consistent and readable way.

Let's say two developers come up with different formats to store a video game save file:

File: Output save game file (FORMAT 1)

RachelsGame
5
1000
RegnierCenter

File: Output save game file (FORMAT 2)

SAVEGAME        RachelsGame
LEVEL           5
GOLD            1000
LOCATION        RegnierCenter
  • For FORMAT 1, we would have to make sure to write our program so that it always saves and loads in the specific order: GAME-NAME, LEVEL, GOLD, LOCATION.
  • For FORMAT 2, since labels are added, we could read in a label, then decide whether the next thing to load in is the GAME-NAME, LEVEL, GOLD, or LOCATION. However, the extra information ("SAVEGAME", "LEVEL", "GOLD", "LOCATION") adds extra storage space to savegame file, and that information is mostly just useful to the humans reading it.

If every save file from the program is formatted in the same way (FORMAT 1), then when reading the file we can make assumptions…

  • First word: Save game name - store in gameFileName.
  • Second word: Player's level - store in level.
  • Third word: Player's gold - store in gold.
  • Fourth word: Player's location - store in location.

…And so on. This could work, but we could also take advantage of those human-readable labels that were added into the file (FORMAT 2):

  • Read firstWord.
  • If firstWord is "SAVEGAME", then read the next word into gameFileName.
    • Else if firstWord is "LEVEL", then read the next word into level.
    • Else if firstWord is "GOLD", then read the next word into gold.
    • Else if firstWord is "LOCATION", then read the next word into location.

So, let's say we have our four variables for a save game:

Name Data type
gameFileName string
level int
gold int
location string

When we go to save our game file, here is what both formats' save process would look like:

Example: Saving for FORMAT 1

// Save the game
ofstream output( "save.txt" );
output << gameFileName << endl;
output << level << endl;
output << gold << endl;
output << location << endl;

File output: Saved game file:

SAVEGAME MyGame
LEVEL    1
GOLD     10
LOCATION OCB

Example: Saving for FORMAT 2

// Save the game
ofstream output( "save.txt" );
output << "SAVEGAME " << gameFileName << endl;
output << "LEVEL    " << level << endl;
output << "GOLD     " << gold << endl;
output << "LOCATION " << location << endl;

File output: Saved game file:

SAVEGAME MyGame
LEVEL    1
GOLD     10
LOCATION OCB

Now, to load in each format, we would have to take a couple of different approaches.

Example: Loading for FORMAT 1

For this format, the savegame data would have to always be in the same order, so we know we also load the data in the same order.

// Load the game
string buffer;
ifstream input( "save.txt" );
input >> gameFileName;
input >> level;
input >> gold;
input >> location;

Example: Loading for FORMAT 2

This one has the helper labels so we read in the first word, investigate what it says, and based on that decide which variable we're loading into next.

string buffer;
ifstream input( "save.txt" );

while ( input >> buffer )
{
  if ( buffer == "SAVEGAME" )
    input >> gameFileName;

  else if ( buffer == "LEVEL" )
    input >> level;

  else if ( buffer == "GOLD" )
    input >> gold;

  else if ( buffer == "LOCATION" )
    input >> location;
}

If we stepped through this, buffer is always going to store one of the data labels, because after buffer is read, we immediately read the second item in the line of text. Once the second item is read, the next thing to be read will be the next label.

Review 13. Which format would this snippet of code write out?

// Save the game
ofstream output( "save.txt" );
output << gameFileName << endl;
output << level << endl;
output << gold << endl;
output << location << endl;

Review 14. Which format would this snippet of code write out?

// Save the game
ofstream output( "save.txt" );
output << "SAVEGAME " << gameFileName << endl;
output << "LEVEL    " << level << endl;
output << "GOLD     " << gold << endl;
output << "LOCATION " << location << endl;

Review 15. Which format would this snippet of code load in?

string buffer;
ifstream input( "save.txt" );

while ( input >> buffer )
{
  if ( buffer == "SAVEGAME" )
    input >> gameFileName;

  else if ( buffer == "LEVEL" )
    input >> level;

  else if ( buffer == "GOLD" )
    input >> gold;

  else if ( buffer == "LOCATION" )
    input >> location;
}

Review 16. Which format would this snippet of code load in?

// Load the game
string buffer;
ifstream input( "save.txt" );
input >> gameFileName;
input >> level;
input >> gold;
input >> location;

6. Working with files in the Real World

Usually you would be working with some kind of library that handles serializing data between its file format to models in the program code, or at least handles reading and parsing the data file and provides a format that's easier for you to use to fill in that data model in the program.

JSON (JavaScript Object Notation) is widely used on the web, especially to transmit data between client (your web browser) and server (a web host).

json.png

Figure 3: The Firefox network inspector showing a JSON response from GitLab

Other common formats are XML, CSV, or even Binary files.

There are also databases, but those work differently from just storing a plaintext file on your system.

xml.png

Figure 4: An XML view of the NPR RSS feed.

Author: RachelWil

Created: 2026-10-14 Wed 11:12

Validate