17: Files

UC Irvine - Fall ‘22 - ICS 45C

Quick list of things I want to talk about:

  • file streams

Expanded notes:

Using files for storage is a way to make information persistent, so we don’t need to recalculate things whenever we need them. C++ provides ways of handling files through file streams, similar to what we’ve used with cout/cin and stringstreams.

Writing to a file

In our first example, let’s create a file and write to it through code:

#include <fstream>

using std::ofstream;

int main() {
  ofstream outFile;
  outFile.open("test.txt");
  outFile << "Hello!" << 123 << '\n' << 1.43;
  outFile.close();
  return 0;
}

This code should not print anything on your screen. Instead, it will create a file called test.txt on the same directory that you ran your binary. It does that with the .open method since this is an ofstream (output file stream). Inside that file, we added the string Hello! with the usual << operator, and finally, we close the file, so all changes get flushed.

Also, note that we need to include the <fstream> (file stream) module.

Reading from a file

Reading from a file is pretty similar, we’re just going to use ifstream (input file stream) instead. Let’s try reading the file we just created as an example:

#include <fstream>
#include <iostream>
#include <string>

using std::ifstream;
using std::cout;
using std::getline;
using std::string;

int main() {
  ifstream inFile;
  string text;
  inFile.open("test.txt");
  while (getline(inFile, text)) {
      cout << text << '\n';
  }
  inFile.close();
  return 0;
}

This should print this to the screen:

Hello!123
1.43

matching what we added into the file with our previous code.

Binary files

The two above examples deal with text files, so we’re writing and reading text with those streams. However, there are files that use binary data, they don’t need to convert from binary values into text (e.g., png images).

For those types of files, we can add a flag (ios::binary) to the open command so the compiler knows we’re dealing with a binary file. Additionally, we should use write and read methods, instead of using << and >>, which allows you to work directly with bytes, instead of converting to/from text.

As an example, let’s try printing out the contents of the image at the very top of this page. If you right-click on it and download it, you should have a file named featured.png. The example code below assumes you’ve downloaded that image and placed it in the same directory as the code.

// Example adapted from: https://cplusplus.com/doc/tutorial/files/

#include <fstream>
#include <iostream>

using namespace std;

int main() {
  streampos size;
  char * memblock;
  ifstream inBinFile("featured.png", ios::in|ios::binary|ios::ate);

  if (inBinFile.is_open()) {
    size = inBinFile.tellg();
    memblock = new char [size];
    inBinFile.seekg (0, ios::beg);
    inBinFile.read (memblock, size);
    inBinFile.close();

    cout << "Binary data: ";
    cout << hex;
    for (int i=0; i < size; i++) {
      cout << (short) memblock[i];
    }
    cout << '\n';

    delete[] memblock;
  } else {
    cout << "Unable to open file";
  }

  return 0;
}

Further reading

References: