Как определить конец файла c
Перейти к содержимому

Как определить конец файла c

  • автор:

Правильное использование проверки конца файла

в C++ получаются неприятности — лишняя считанная строка, например. Почему? Как правильно проверить, что достигнут конец файла?

Harry's user avatar

Признак достижения конца файла выставляется только после неудачной попытки чтения за его концом. Поэтому, если в теле цикла нет проверки, успешно ли выполнено чтение из файла — последнее чтение окажется именно тем неудачным чтением, которое выставит признак достигнутого конца файла (а для вас это будет выглядеть как, например, еще раз считанная последняя строка, если она находилась в буфере для чтения).

Лучше в заголовке цикла while выполнять само чтение с проверкой — например, в программе на C это могло бы выглядеть как

Определение конца файла

Обычной файловой операцией в ваших программах является чтение содержимого файла, пока не встретится конец файла. Чтобы определить конец файла, ваши программы могут использовать функцию еоf потокового объекта. Эта функция возвращает значение 0, если конец файла еще не встретился, и 1, если встретился конец файла. Используя цикл while,ваши программы могут непрерывно читать содержимое файла, пока не найдут конец файла, как показано ниже:

В данном случае программа будет продолжать выполнять цикл, пока функция eof возвращает ложь (0). Следующая программа использует функцию eof для чтения содержимого файла file.txt, пока не достигнет конца файла:

Аналогично, следующая программа читает содержимое файла по одному слову за один раз, пока не встретится конец файла:

И наконец, следующая программа читает содержимое файла по одному символу за один раз, используя функцию get, пока не встретит конец файла:

Закрытие файла, если он больше не нужен

При завершении вашей программы операционная система закроет открытые ею файлы. Однако, как правило, если вашей программе файл больше не нужен, она должна его закрыть. Для закрытия файла ваша программа должна использовать функцию close, как показано ниже:

Когда вы закрываете файл, все данные, которые ваша программа писала в этот файл, сбрасываются на диск, и обновляется запись каталога для этого файла.

Ввод/вывод данных с помощью функций унаследованных от с

Поток в C++ — последовательность байтов, независимых от конкретного устройства, с которого производится считывание данных.

Работа с потоком начинается с его открытия. Поток можно открыть для чтения и/или записи в двоичном или текстовом режиме. Функция открытия потока имеет формат:

FILE* fopen(const char* filename, const char* mode);

FILE – специальный тип данных, содержащий информацию необходимую для выполнения операций с файлом.

Первый параметр — имя открываемого файла в виде строки, второй — режим открытия файла:

«г» — файл открывается для чтения;

«w» — открывается пустой файл для записи (если файл существует, он стирается);

«а» — файл открывается для добавления информации в его конец;

«г+» — файл открывается для чтения и записи (файл должен существовать);

«W+ » — открывается пустой файл для чтения и записи (если файл существует, он стирается);

«а+» — файл открывается для чтения и добавления информации в его конец.

Режим открытия может также содержать символы t (текстовый режим) или b (двоичный режим), отличающиеся обработкой символов перехода на новую строку. По умолчанию файл открывается в текстовом режиме. Текстовый файл трактуется в С++ как совокупность символьных строк переменной длины. Доступ к каждой строке возможен лишь последовательно, начиная с первой. При создании текстовых файлов в конце каждой строки ставится специальный признак EOL (кодируется последовательностью кодов 13 и 10), а в конце всего файла – признак конца файла (код 26).

В двоичном режиме эти преобразования не выполняются.

FILE * f = fopen(«d:\\cpp\\clata». «rb+»);

Имя функции является указателем на ее расположение в памяти, поэтому знак равенства допустим. Присваивание указателю адреса функции fopen необходимо для того, чтобы ее можно было использовать в других функциях (методах).

Указатель f используется в дальнейших операциях с потоком. Его передают функциям ввода/вывода в качестве параметра. При открытии потока с ним связывается область памяти, называемая буфером. Это делается для увеличения скорости передачи данных.

При выводе вся информация направляется в буфер и накапливается там до заполнения буфера или до закрытия потока. Чтение осуществляется блоками, равными размеру буфера, и данные читаются из буфера. Следует иметь в виду, что при аварийном завершении программы выходной буфер может быть не выгружен, и возможна потеря данных.

Ввод/вывод в поток

Ввод/вывод в поток можно осуществлять различными способами: в виде последовательности байтов, в виде символов и строк или с использованием форматных преобразований.

Операции ввода/вывода выполняются начиная с текущей позиции потока, определяемой положением указателя потока. Указатель устанавливается при открытии на начало или конец файла (в соответствии с режимом открытия) и изменяется автоматически после каждой операции, ввода/вывода. Текущее положение указателя можно получить с помощью функций ftel1 и fgetpos и задать явным образом с помощью функций fseek и fsetpos. Эти функции нельзя использовать для стандартных потоков (stdin — стандартный поток ввода данных, stdout — стандартный поток вывода данных и stderr — стандартный поток ошибок).

• Чтение и запись потока байтов выполняют функции fread и fwrite.

• Чтение символа из потока — getc, fgetc, из стандартного потока stdin — getchar.

• Запись символа в поток — put с, fputc, в стандартный поток stdout — putchar.

• Чтение строки из потока — fgets, из стандартного потока stdin — gets.

• Запись строки в поток — fputs, в стандартный поток stdout — puts.

• Форматированный ввод из потока — fscanf, из стандартного потока stdin —scanf, из строки — sscanf.

• Форматированный вывод в поток — fprintf, в стандартный поток stdout —printf, в строку — sprintf.

Поток закрывается либо при завершении программы, либо явным образом с помощью функции fclose:

int fclose(FILE*):

Перед закрытием потока информация из связанных с ним буферов выгружается на диск. Рекомендуется всегда явным образом закрывать потоки, открытые для записи, чтобы избежать потери данных.

Функции работы с потоком возвращают значения, которые рекомендуется анализировать в программе и обрабатывать ошибочные ситуации, возникающие, например, при открытии существующих файлов или чтении из потока. При работе с файлами часто используются функции feof и terror:

int feof (FILE*) возвращает не равное нулю значение, если достигнут конец файла, в противном случае 0;

int terror (FILE*) возвращает не равное нулю значение, если обнаружена ошибка ввода/вывода, в противном случае 0.

Примеры чтения строк и символов из файла

FILE *f=fopen(«d:\\data.txt»,»r»); открываем файл в режиме чтения (“r”)

while (!feof(f)) пока не конец файла

c=fgetc(f); считываем очередной символ

cout<<c<<‘\n’;> выводим построчно считанные символы

cout<<i; выводим общее количество символов

char s[150]; int i=0;

while(fgets(s,150,f)) Пока не закончатся строки

cout<<s<<‘\n’;> выводим считанную строку

cout<<i; выводим количество строк

Помним, что символ перевода на новую строку также считывается и учитывается в общем количестве.

Методы класса StreamReader

Согласно документации методы Close() и Dispose() имеют следующую общую форму:

Метод Close() закрывает объект типа StreamReader и базовый поток а также освобождает любые системные ресурсы, ассоциированные с этим объектом.

Метод Dispose() закрывает базовый поток, освобождает неуправляемые (unmanaged) ресурсы и позволяет по выбору освобождать управляемые (managed) ресурсы с помощью параметра disposing . Если disposing = true , то освобождаются и управляемые и неуправляемые ресурсы. Если disposing = false , то освобождаются только неуправляемые ресурсы.

Вызвать метод Dispose() с параметром не удастся, поскольку он объявлен как protected . В классе TextReader есть вариант метода Dispose() без параметров, который наследуется классом StreamReader . Этот метод имеет объявления

и может быть вызван из экземпляра типа StreamReader .

Использование метода Close() выглядит следующим образом

Аналогично может быть вызван метод Dispose()

2.2. Метод Peek()

Метод Peek() используется, когда нужно заранее определить следующий символ, который будет прочитан из потока. Метод возвращает следующий символ потока но не перемещает указатель чтения из файла. Согласно документации, объявление метода имеет вид:

Метод возвращает целое число, представляющее следующий символ. Если нет символов в потоке или поток не поддерживает поиск, то метод возвращает -1.

Пример. В примере используется метод Peek() для проверки того, достигнут конец файла. На экран выводится содержимое файла myfile1.txt .

2.3. Метод Read() . Чтение одиночного символа

Для чтения символа из потока ввода используется метод Read() , который имеет следующее объявление

Метод считывает следующий символ из потока ввода и сдвигает указатель чтения из файла на один символ. Метод возвращает прочитанный символ, представленный как тип System.Int32 или -1, если символ не удалось прочитать.
Если файла не существует, генерируется исключение типа System.IOException .

Пример. В примере, с помощью метода Read() происходит посимвольно чтение файла и вывод его содержимого на экран.

2.4. Метод Read(char[], int, int) . Чтение группы символов в буфер

Другая перегруженная реализация метода Read() предназначена для чтения набора символов в указанный буфер и имеет следующее объявление

  • buffer — массив символов, в который считывается содержимое текущего потока ввода. Символы потока записываются в позициях от index до index + count-1 массива buffer ;
  • index — позиция в буфере, с которой начинается считывание;
  • count — максимальное количество считываемых символов.

Метод возвращает количество реально прочитанных символов. Значение прочитанных символов колеблется в пределах от 0 до count . Если не удалось прочитать символы, метод возвращает 0.

При использовании метода обрабатываются следующие исключения:

  • System.ArgumentException — случай, когда длина buffer минус index является меньше чем count ;
  • System.ArgumentNullException — buffer равен null ;
  • System.ArgumentOutOfRangeException — значение index или count отрицательны;
  • System.IO.IOException — случай, когда поток закрыт.

Пример. В примере считывается файл порциями по 10 символов с помощью метода Read() .

2.5. Метод ReadBlock() . Прочитать набор символов из файлового потока

Метод ReadBlock() считывает набор символов из потока ввода в указанный участок памяти. Метод имеет следующее объявление

  • buffer – массив, в который считываются символы из потока. В массиве символы записываются начиная с позиции index до позиции ( index + count — 1 );
  • index — начальная позиция в массиве, в которую считываются символы из потока;
  • count — максимальное количество считываемых символов.

При использовании метода могут быть сгенерированы исключения следующих типов:

  • System.ArgumentException — случай, когда длина buffer минус index является меньше чем count;
  • System.ArgumentNullException — buffer равен null ;
  • System.ArgumentOutOfRangeException — значение index или count есть отрицательными;
  • System.IO.IOException — случай, когда поток закрыт;
  • System.ObjectDisposedException — случай, когда поток StreamReader закрыт.

Пример. В примере считывается содержимое файла в буфер buffer за один раз. Для определения длины файла используется класс FileInfo .

2.6. Метод ReadLine() . Чтение строки

Метод ReadLine() используется для чтения строки из файлового потока. Согласно документации, метод имеет следующее объявление

Метод возвращает строку символов из текущего файлового потока. Если достигнут конец потока, метод возвращает null .

При использовании метода могут возникать исключения следующих типов:

  • System.OutOfMemoryException — случай, когда недостаточно памяти для выделения ее в возвращаемую строку;
  • System.IO.IOException — ошибка ввода/вывода.

Пример. В примере построчно считывается текстовый файл и выводится на экран.

2.7. Метод ReadToEnd()

Метод ReadToEnd() считывает все символы с текущей позиции чтения до конца потока. Объявления метода имеет вид

Метод возвращает поток в виде строки. Если текущая позиция указывает на конец потока, метод возвращает пустую строку «» .

При использовании метода могут возникать исключения следующих типов:

  • System.OutOfMemoryException — случай, когда недостаточно памяти для выделения ее под выделяемую строку;
  • System.IO.IOException — ошибка ввода/вывода.

Пример. В примере выводится содержимое текстового файла на экран. Файл считывается в строку методом ReadToEnd() .

3. Свойства класса StreamReader
3.1. Свойство BaseStream . Получить ссылку на базовый поток

С помощью свойства BaseStream можно получить ссылку на базовый поток Stream . Объявление свойства следующее

Пример. В примере определяется размер файла в байтах с помощью ссылки на базовый поток.

3.2. Свойство CurrentEncoding . Получить кодировку потока

Свойство CurrentEncoding позволяет получить объект, содержащий данные о текущей кодировке в потоке. Объявление свойства следующее:

Чтобы использовать свойство можно написать примерно следующий код

3.3. Свойство EndOfStream . Определить окончание потока

Свойство EndOfStream предназначено для определения того, указывает ли текущая позиция потока на конец потока. Объявление свойства имеет вид

Свойство возвращает true , если текущая позиция потока указывает на его конец. В противном случае свойство возвращает false .

При использовании свойства может возникнуть исключение типа System.ObjectDisposedException .

Пример. В примере осуществляется посимвольно чтение из файла до тех пор, пока не будет достигнут конец файла. Конец файла определяется с помощью свойства EndOfStream .

Функция feof

Функция feof проверяет, достигнут ли конец файла, связанного с потоком, через параметр filestream . Возвращается значение, отличное от нуля, если конец файла был действительно достигнут.
Вызов данной функции, как правило, выполняется после выполнения предыдущей операции с потоком, например операции считывания, которая постепенно двигает внутренний указатель файла в конец.
Дальнейшие операции с файлом, после достижения его конца не будут выполняться до тех пор, пока внутренний указатель не будет сдвинут назад, функциями fseek или fsetpos . Таким образом индикатор положения внутреннего указателя будет иметь новое значение, отличное от EOF .

Параметры:

  • filestream
    Указатель на объект типа FILE , идентифицируемый поток.

Возвращаемое значение

Если достигнут конец файла, функция возвращает ненулевое значение.
В противном случае возвращается нулевое значение.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *