Перейти к основному содержимому

Чтение из файла управляющих символов ASCII и корректная обработка конца файла с помощью EOF в C++

· 3 мин. чтения
Дмитрий Аладин
Преподаватель

В данной статье рассказывается о том, как записывать в файл специальные символы ASCII, а также производить чтение таких символов из файла. Также представлен корректный вариант обработки конца файла с помощью EOF в C++.

Запись управляющих символов ASCII (код символа 0-31)

Чтобы корректно читать и записывать управляющие символы ASCII, рекомендуется открывать файл в бинарном режиме. Основываясь на статье Чтение и запись двоичного файла на C++ | CodeSpeedy, рассмотрим запись и чтение в бинарном режиме.

Запись в двоичный файл

ofstream wf("example.txt", ios::out | ios::binary);
if (!wf.is_open()) {
cout << "Cannot open file!" << endl;
return 1;
}
// ...
// Записываем в файл
// ...
wf.close();
if (!wf.good()) {
cout << "Error occurred at writing time!" << endl;
return 1;
}

Чтение из двоичного файла

ifstream rf("example.txt", ios::in | ios::binary);
if (!rf.is_open()) {
cout << "Cannot open file!" << endl;
return 1;
}
// ...
// Читаем из файла
// ...
rf.close();

Корректная обработка конца файла с помощью EOF в C++

Основываясь на статье Корректная обработка конца файла с помощью EOF в C ++ | TheLinuxCode и ответе на вопрос How does ifstream's eof() work? | stackoverflow, необходимо отметить следующее:

  1. C++ предоставляет простой способ проверки конца файла с помощью eof() метода. Это наиболее распространенный метод, используемый для надежной обработки EOF:

    stream.eof(); 

    Аргументы не требуются. Он возвращает bool, указывающий, достигнут ли EOF.

  2. Флаг EOF устанавливается только после попытки чтения после конца файла. Если имеется 3-байтовый файл, и было прочитано только 3 байта, EOF равен false потому, что еще не пытались прочитать дальше конца файла. Хотя это кажется запутанным для файлов, размер которых обычно известен, EOF не известен до тех пор, пока не будет предпринята попытка чтения на некоторых устройствах, таких как каналы и сетевые сокеты.

  3. Всегда проверяйте eof() после операции чтения, никогда до:

    while (stream.get(ch)) {
    // обрабатываем данные
    }

    if (stream.eof()) {
    // обрабатываем EOF
    }

Иллюстрирующий пример

Следующий пример показывает то, как записать управляющие символы ASCII с 0 по 31, а также корректно обработать завершение файла:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
// Открываем файл на запись в бинарном режиме
ofstream wf("example.txt", ios::out | ios::binary);
if (!wf.is_open()) {
cout << "Unable to open file for write" << endl;
return -1;
}
// Записываем специальные символы с кода 0 по 31
for (int i = 0; i < (int)' '; i++) {
wf << (char)(i);
}
wf.close();
if (!wf.good()) {
cout << "Error occurred at writing time!" << endl;
return 1;
}
// Открываем файл на чтение в бинарном режиме
ifstream rf("example.txt", ios::in | ios::binary);
if (!rf.is_open()) {
cout << "Unable to open file for read" << endl;
return 1;
}
char c;
// Обратите внимание, что проверка на eof() выполняется
// после операции чтения, никогда до!
// Подробнее: https://thelinuxcode.com/eof-cpp/
while (rf.get(c)) {
cout << "symbol: " << (int)c << endl;
}
if (rf.eof()) {
cout << "EOF" << endl;
}
rf.close();
return 0;
}