File streams

File stream objects

The stream classes to read/write from/to files are std::ifstream, which inherit from std::istream, std::ofstream, which inherit from std::ostream, and std::fstream, which inherit from std::iostream.

We can output/input to/from them using the stream operators or the input/output methods defined in std::istream and std::ostream.

Opening a file

If we give no argument to the constructor of the file stream object, the stream will not be linked to any file. We will then have to use the method void std::fstream::open(const char* filePath, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out). This method is the same for the classes std::ifstream and std::ofstream, except that the default value of the last argument is different. The first argument is a pointer to a constant null-terminated string representing the path to the file to open and the second one is the opening mode of the file. Here is a table with the possible opening modes:

Value (flag)Meaning
std::ios::inFile opened for input operations.
std::ios::outFile opened for output operations.
std::ios::ateThe stream cursor starts at the end of the file, instead of the beginning.
std::ios::appAll output operations will write at the end of the file.
std::ios::binaryThe file is opened as a binary file. By default, it is opened in text mode.
std::ios::truncThe content of the file is erased.

We can combine those values (flags) by using the | bitwise operator (OR).

The flags std::ios::in and std::ios::out can be used with std::fstream to open the file in input mode only, output only or both. They should not be used with std::ifstream or std::ofstream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <fstream> int main() { std::ofstream file; /* Opens the file located at "file.bin", in binary/append mode. */ file.open("file.bin", std::ios::binary | std::ios::app); float array[] = {5.5, 6.6, 7.7, 8.8}; /* Appends the binary data (bytes) of four floating point numbers to the file stream. */ file.write((char*)array, sizeof(array)); return 0; }

Note that opening (In output mode) a file that does not exist has the effect of creating it, but we can not create folders that way.

File stream classes have a constructor overload that takes the same arguments as the method std::fstream::open. By using it, we can open a file at the creation of a stream object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <fstream> #include <iostream> int main() { /* Opens the file located at "file.txt", in the default opening mode of an input file stream (input/text mode). */ std::ifstream file("file.txt"); float value; /* Reads a floating point number from the file stream, which has to be stored in text ("99.56") rather than binary, because the stream operators of streams from the C++ Standard Library are defined to input/output data from/to text. */ file >> value; // Outputs the floating point number read from the file stream. std::cout << value << std::endl; return 0; }

Closing a file

Unlike with file stream objects from the C Standard Library, with the C++ Standard Library, we do not have to manually close them as they are automatically closed by their destructor. It is however possible to manually close them so we can open other files (Or the same, but with a different opening mode) with the same stream objects. The method used to close the file linked to a file stream is void std::fstream::close().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <fstream> #include <iostream> int main() { /* Opens the file located at "file.bin", in output/binary mode. It is created if it does not exist. */ std::fstream file("file.bin", std::ios::out | std::ios::binary); int values[] = {5, 90, 34, 76}; /* Outputs the bytes of 4 integers into the file stream. */ file.write((char*)values, sizeof(values)); // Closes the file linked to the file stream. file.close(); /* Opens, again, the file located at "file.bin", but in input/binary mode. */ file.open("file.bin", std::ios::in | std::ios::binary); int readValues[4]; /* Reads the bytes of 4 integer numbers, from the file stream, into the array of integers 'readValues'. */ file.read((char*)readValues, sizeof(readValues)); // Prints, to the console, the floating numbers read. for(unsigned c=0; c < 4; c++) { std::cout << readValues[c] << std::endl; } return 0; }

Looking if a stream is linked to an opened file

The method bool std::fstream::is_open() returns true if the file stream is linked to an opened file. Otherwise, it returns false. For example, if a file stream unsuccessfully tries to open a file (Because the file does not exist or the creation of the file has failed), the method is_open will return false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <fstream> #include <iostream> int main() { std::ifstream file; if(!file.is_open()) // is_open will return false std::cout << "The stream is not linked to an opened file." << std::endl; file.open("files/file.txt"); if(file.is_open()) std::cout << "File successfully opened!" << std::endl; else std::cout << "The file at the path given in argument does not exist!" << std::endl; return 0; }

Flushing the stream

The buffer of buffered streams (File streams are buffered) are automatically flushed when it is full or the stream object is destroyed. With the method std::ostream& std::ostream::flush(), we can manually flush the buffer of the output stream object it is called from (If it is buffered).

Just a remainder that buffered output streams are streams that, instead of directly writing to the devices/locations linked to them, they output to a buffer and when it is full or the stream is flushed, they write its content to the destination of the stream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <fstream> int main() { std::ofstream file("file.bin", std::ios::binary); unsigned array[] = {7865, 3535, 34534}; file.write((char*)array, sizeof(array)); /* Here, the bytes of 'array' are still in the buffer of the stream object (And thus not in the file). */ file.flush(); /* Now, the bytes from the buffer of the stream file are written to the file linked to it. */ return 0; }

Note that unbuffered streams, the newline character '\n' and std::endl have the same effect. However, std::endl flushes the stream it is outputted to, so it should be avoided with buffered streams (Like file streams).