File I/O

  1. Overview
    1. All programs we have created up to this point read input from the keyboard and send output to the console
    2. Most useful programs get input from and send output to other sources like files, databases, networks, etc.
    3. File I/O (input/output) is the simplest method of retrieving large amounts of input and for storing large amounts of output
    4. We will only cover reading from and writing to files that reside on the computer's hard drive
  2. Types of files
    1. Two main types of files: text and binary
    2. Text file
      1. Composed of bytes that equate to textual data (1 byte per character)
      2. Can be created by any text editor (Notepad, Visual Studio, etc.)
      3. Usually saved with a .txt extension, but any file extension is acceptable (.cpp files are text files)
    3. Binary file
      1. Composed of bytes that do not equate to textual data
      2. Opening a binary file into a text editor usually displays gibberish because each byte is converted into an extended ASCII character
      3. Images, audio, and video are almost always stored in binary files
    4. Text files are easier to work with than binary files in C++, so we will start with text files
  3. Reading from an input file
    1. The input file must exist before the program attempts to read from it
    2. Include fstream to use file I/O classes
      #include <fstream>
      
    3. ifstream class for opening a file for input
    4. Example reading in three numbers from file
      1. Suppose a file called nums.txt contained three numbers:
        5
        1
        8
        
      2. Example that reads the three numbers from the file above and displays the sum
        int x, y, z;
        ifstream fin;
        
        // Open the file which already exists
        fin.open("nums.txt");
        
        // Reads 5, 1, and 8 into x, y, and z
        fin >> x >> y >> z;
        
        cout << "Sum of numbers is " << (x + y + z);   // 14
        
        // Always close what you open
        fin.close();
        
    5. Important methods
      1. open("filename") - opens an existing file (must be in the same directory as the .cpp file)
      2. ifstream >> variable - reads numbers from the given ifstream into the variable
      3. close() - closes the connection between the file and the variable
    6. Reading until EOF
      1. In most cases, the amount of data in a file to be read is not known ahead of time
      2. Use a loop to read in data until the end of file (EOF) is reached
      3. good() - returns true if the previous read operation was successful, false otherwise
      4. Example that reads any number of numbers
        int x, total = 0;
        ifstream fin;
        
        fin.open("nums.txt");
        
        // Read the first number 
        fin >> x;
        
        // Loop until there are no numbers left in the file
        while (fin.good())
        {
        	total += x;
        	
        	// Read the next number
        	fin >> x;
        }
        
        cout << "Sum of numbers is " << total;
        
        fin.close();
        
    7. Reading strings from a file
      1. Use getline(ifstream, string) to read a string from an ifstream
      2. fail() - returns true if the prevous read operation failed to read anything (because no bytes left to read)
      3. Using !fail() instead of good() is preferred when reading strings because good() returns false if the last string in the file does not have a newline char at the end
      4. Given the following poem.txt file:
        Roses are red,
        Violets are blue.
        Here is a poem
        That doesn't rhyme.
        
        Here is a program that reads the poem.txt file and outputs the contents to the console
        string line;
        ifstream fin;
        
        // Open the existing poem.txt file
        fin.open("poem.txt");
        
        // Read the first line from the file
        getline(fin, line);
        
        // Loop until we reach the end of the file
        while (!fin.fail())
        {
        	cout << line << endl;
        	
        	// Get the next line from the file
        	getline(fin, line);
        }
        
        // Done reading from the file
        fin.close();
        
  4. Testing for file open success
    1. What if the file to be read was moved to a different directory, renamed, or deleted?
    2. Use is_open() to determine if open() was successful - returns true if open failed
      ifstream fin;
      fin.open("nums.txt");
      
      // Did we fail to open the file?
      if (!fin.is_open())
      {
      	cout << "Could not open nums.txt for reading.";
      
      	// Terminate the application
      	exit(0);
      }
      
    3. Always a good idea to use fail() after attempting to open an input file