JUGInformation Engineering Laboratory - Semester 1

10 - Files

10 - Files


🔨 🔥 Assignment 🔥 🔨

Create a new project in the way explained in the first instruction.


Text files in C++

C++ can handle files using mechanism called file streams. In order to use them, we need to include the <fstream> library:

#include <fstream>

Similarly to FILE pointer in C, we have std::fstream:

std::fstream file;

To open a file, we can use method open:

void std::fstream::open(std::string filename, std::ios_base::openmode mode);

Available modes:

Example - opening file “test.txt” for reading and writing (it is possible to join modes with character | ):

std::fstream file;
file.open("test.txt", std::ios::in | std::ios::out);

To check if the file was correctly opened you can use functions is_open() or good(), which return true or false:

std::fstream file;
file.open("test.txt", std::ios::in | std::ios::out);
if (file.is_open()) {
    std::cout << "File was correctly opened!" << std::endl;
}

To close a file, we can use close() method:

file.close();

In case of C++ fstreams it is possible to read from them in a similar way to the reading with std::cin:

char letter;
double number;
file >> letter >> number;

or write back to the file:

char letter = 'A';
file << letter << 1.23456;

It is also possible to read a whole line with getline():

std::string line;
std::getline(file, line);

To read all of the information in the file, it is possible to write a loop and check if we reached the end of the file with eof() method:

while(!file.eof()) {
    int number;
    file >> number;
}

or when using getline():

std::string line;
while(std::getline(file, line)) {
    //process a single line
}

ATTENTION In C++, we can create a default reading stream by using ifstream (instead of fstream) or a default writing stream by using ofstream (instead of fstream). Example:

std::ifstream file; // Default reading stream
file.open("name.txt");

🔨 🔥 Assignment 🔥 🔨

  1. Using a plain text editor such as Notepad, Notepad++ or Visual Studio Code create a simple text file and fill it with some words (texts) separated by spaces. Open the file in your program and print each word in a separate line on the screen.

  2. Read the same file, but store the words in a variable (eg. using std::vector) and then write it to the new file but in reverse order.

Example original file:

aaa bbb ccc

Example output file:

ccc bbb aaa

  1. Close and open the output file once again. Append a single line to the end, but do not clear the previously written data.

  2. Read the data about students from the file under the LINK. Store the information about the students in the std::vector of prepared structures. Then:

    • print the content,
    • ask user for a new student info, add as many students as the user wants to,
    • ask user which students should be removed (by providing their last name), remove as many students the user wants to,
    • sort all students based on their grade (from lowest to highest),
    • save all data to a new file in the same format.

Text files vs binary files

In text files the information is stored as characters as in case of binary files the information is stored directly as an information in the memory. Let’s consider an example in which we would only write the Pi number (3.14159265359) into text and binary files. Now let’s see both files in the text editor (like notepad++):

3.14159

ę.DTű! @

For the text file, each digit of the number was converted to the character and then written to the file. If we would need to read the number back to the program, we would lose some precision as the number we stored has only 5 digits after decimal point. In case of a binary file, the number is written to the file as a sequence of bytes. Therefore, even if not easily readable by humans, the number is stored with greater precision.

What happens when we try to store text in a file. Let’s try to write Programming class to text and binary files:

Programming class

Programming class

In case of characters, the sequence of bytes directly corresponds to the visual characters, which results in the same files for text and binary files.

The binary files are faster than text files as you don’t need to translate each byte to character. But it is necessary to remember that the representation in the memory depends on the compiler (the size of the type in a memory) and on the architecture of the CPU (little endian or big endian). Therefore, reading the same file on different computers might provide different results or even fail.

Moving inside file in C++

Sometimes, it is necessary to read the file again or just move from the current position in a file. To do this, we can use:

istream& std::istream::seekg (streamoff off, ios_base::seekdir way); // For reading files
ostream& std::iotream::seekp (streamoff off, ios_base::seekdir way); // For writing files

where off means the offset and way specifies the relation of this offset. Way can have the following values:

Therefore, setting the off to 1 and way to std::ios::beg means that we move our position in a file to 1 with respect to the beginning. The example:

std::ofstream file;
file.seekp(0, std::ios::beg); // Moves to the beginning
file.seekp(0, std::ios::end); // Moves to the end

Finding element separators in lines

In many cases the data in a text file is not separated by spaces ( ), but other, special ASCII characters. Eg. in case of CSV (Comma Separated Values), a comma (,) is the separating character. find() LINK and substr() LINK methods of std::string can be used to extract elements in lines:

std::string line = "John;Important;London"; // single line read from file

size_t pos;                                 // variable for storing separator position, size_t is simply an integer type

pos = line.find(';');                       // find position of first spearator
std::string name = line.substr(0, pos);     // copy of a substring from position 0 to pos
line = line.substr(pos+1, line.length());   // assign line with a substring without first element

pos = line.find(';');
std::string surname = line.substr(0, pos);

std::string city = line.substr(pos+1); // remaining, last element

This procedure can be looped if needed, or modified to handle unknown number of elements, as find() method will return std::string::npos if the specified character is not found.

Converting std::string to numerical values

In order to convert characters in std::string into numerical variables following functions can be used:

std::string s1 = "1234";
int i1 = std::stoi(s1);
std::cout << i1 + 1000 << std::endl;

std::string s2 = "250 km/h";
int i2 = std::stoi(s2);
std::cout << i2 << std::endl;

std::string s3 = "1.434";
double d1 = std::stod(s3);
std::cout << d1 << std::endl;

2234
250
1.434

Final assignments 🔥 🔨

Exercise 1

Read a file containing information about the fastest cars: LINK. Create functions that answer following questions:

Exercise 2

Read a file containing the list of countries that produce the most oil: LINK created based on WIKI. The first column contains country name and information if the country belongs to OPEC group. The second column informs about the number of barrels created daily. Do the following tasks:

Homework 💥 🏠

You are responsible for processing the information about the demography in Poland provided in a file (LINK). The first line informs about the content of the file: the first column is the name of the voivodeship, then we have number of men living in cities, number of women living in cities, number of men living in villages and the number of women living in villages. Please allow user to perform following tasks that should be chosen from the menu (the program ends when x or X is read):


Authors: Michał Nowicki, Jan Wietrzykowski, Dominik Pieczyński, Tomasz Mańkowski