Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 12: File I/O

C++ file I/O is done via streams. The key abstractions are:

std::istream for reading text.

std::ostream for writing text.

std::streambuf for reading or writing characters.

Formatted input uses operator>>.

Formatted output uses operator<<.

Streams use std::locale, e.g., for details of the formatting and for translation between external encodings and the internal encoding.

More on streams: <iostream> Library

Section 12.1: Writing to a file

There are several ways to write to a file. The easiest way is to use an output file stream (ofstream) together with the stream insertion operator (<<):

std::ofstream os("foo.txt"); if(os.is_open()){

os << "Hello World!";

}

Instead of <<, you can also use the output file stream's member function write():

std::ofstream os("foo.txt"); if(os.is_open()){

char data[] = "Foo";

// Writes 3 characters from data -> "Foo". os.write(data, 3);

}

After writing to a stream, you should always check if error state flag badbit has been set, as it indicates whether the operation failed or not. This can be done by calling the output file stream's member function bad():

os << "Hello Badbit!"; // This operation might fail for any reason. if (os.bad())

// Failed to write!

Section 12.2: Opening a file

Opening a file is done in the same way for all 3 file streams (ifstream, ofstream, and fstream).

You can open the file directly in the constructor:

std::ifstream ifs("foo.txt"); // ifstream: Opens file "foo.txt" for reading only.

std::ofstream ofs("foo.txt"); // ofstream: Opens file "foo.txt" for writing only.

GoalKicker.com – C++ Notes for Professionals

54

std::fstream iofs("foo.txt"); // fstream: Opens file "foo.txt" for reading and writing.

Alternatively, you can use the file stream's member function open():

std::ifstream ifs;

ifs.open("bar.txt"); // ifstream: Opens file "bar.txt" for reading only.

std::ofstream ofs;

ofs.open("bar.txt"); // ofstream: Opens file "bar.txt" for writing only.

std::fstream iofs;

iofs.open("bar.txt"); // fstream: Opens file "bar.txt" for reading and writing.

You should always check if a file has been opened successfully (even when writing). Failures can include: the file doesn't exist, file hasn't the right access rights, file is already in use, disk errors occurred, drive disconnected ...

Checking can be done as follows:

// Try to read the file 'foo.txt'.

std::ifstream ifs("fooo.txt"); // Note the typo; the file can't be opened.

// Check if the file has been opened successfully. if (!ifs.is_open()) {

// The file hasn't been opened; take appropriate actions here. throw CustomException(ifs, "File could not be opened");

}

When file path contains backslashes (for example, on Windows system) you should properly escape them:

// Open the file 'c:\\folder\\foo.txt' on Windows.

std::ifstream ifs("c:\\\\folder\\\\foo.txt"); // using escaped backslashes

Version ≥ C++11

or use raw literal:

// Open the file 'c:\\folder\\foo.txt' on Windows.

std::ifstream ifs(R"(c:\\folder\\foo.txt)"); // using raw literal

or use forward slashes instead:

// Open the file 'c:\\folder\\foo.txt' on Windows. std::ifstream ifs("c:/folder/foo.txt");

Version ≥ C++11

If you want to open file with non-ASCII characters in path on Windows currently you can use non-standard wide character path argument:

// Open the file 'пример\\foo.txt' on Windows.

std::ifstream ifs(LR"(пример\\foo.txt)"); // using wide characters with raw literal

Section 12.3: Reading from a file

There are several ways to read data from a file.

If you know how the data is formatted, you can use the stream extraction operator (>>). Let's assume you have a file named foo.txt which contains the following data:

GoalKicker.com – C++ Notes for Professionals

55

John Doe 25 4 6 1987

Jane Doe 15 5 24 1976

Then you can use the following code to read that data from the file:

// Define variables. std::ifstream is("foo.txt"); std::string firstname, lastname; int age, bmonth, bday, byear;

//Extract firstname, lastname, age, bday month, bday day, and bday year in that order.

//Note: '>>' returns false if it reached EOF (end of file) or if the input data doesn't

//correspond to the type of the input variable (for example, the string "foo" can't be

//extracted into an 'int' variable).

while (is >> firstname >> lastname >> age >> bmonth >> bday >> byear) // Process the data that has been read.

The stream extraction operator >> extracts every character and stops if it finds a character that can't be stored or if it is a special character:

For string types, the operator stops at a whitespace () or at a newline (\n).

For numbers, the operator stops at a non-number character.

This means that the following version of the file foo.txt will also be successfully read by the previous code:

John

Doe 25

4 6 1987

Jane Doe 15 5 24 1976

The stream extraction operator >> always returns the stream given to it. Therefore, multiple operators can be chained together in order to read data consecutively. However, a stream can also be used as a Boolean expression (as shown in the while loop in the previous code). This is because the stream classes have a conversion operator for the type bool. This bool() operator will return true as long as the stream has no errors. If a stream goes into an error state (for example, because no more data can be extracted), then the bool() operator will return false. Therefore, the while loop in the previous code will be exited after the input file has been read to its end.

If you wish to read an entire file as a string, you may use the following code:

// Opens 'foo.txt'. std::ifstream is("foo.txt"); std::string whole_file;

//Sets position to the end of the file. is.seekg(0, std::ios::end);

//Reserves memory for the file.

whole_file.reserve(is.tellg());

// Sets position to the start of the file. is.seekg(0, std::ios::beg);

GoalKicker.com – C++ Notes for Professionals

56

// Sets contents of 'whole_file' to all characters in the file. whole_file.assign(std::istreambuf_iterator<char>(is),

std::istreambuf_iterator<char>());

This code reserves space for the string in order to cut down on unneeded memory allocations.

If you want to read a file line by line, you can use the function getline():

std::ifstream is("foo.txt");

// The function getline returns false if there are no more lines. for (std::string str; std::getline(is, str);) {

// Process the line that has been read.

}

If you want to read a fixed number of characters, you can use the stream's member function read():

std::ifstream is("foo.txt"); char str[4];

// Read 4 characters from the file. is.read(str, 4);

After executing a read command, you should always check if the error state flag failbit has been set, as it indicates whether the operation failed or not. This can be done by calling the file stream's member function fail():

is.read(str, 4); // This operation might fail for any reason.

if (is.fail())

// Failed to read!

Section 12.4: Opening modes

When creating a file stream, you can specify an opening mode. An opening mode is basically a setting to control how the stream opens the file.

(All modes can be found in the std::ios namespace.)

An opening mode can be provided as second parameter to the constructor of a file stream or to its open() member function:

std::ofstream os("foo.txt", std::ios::out | std::ios::trunc);

std::ifstream is;

is.open("foo.txt", std::ios::in | std::ios::binary);

It is to be noted that you have to set ios::in or ios::out if you want to set other flags as they are not implicitly set by the iostream members although they have a correct default value.

If you don't specify an opening mode, then the following default modes are used:

ifstream - in

ofstream - out

fstream - in and out

The file opening modes that you may specify by design are:

GoalKicker.com – C++ Notes for Professionals

57