Смекни!
smekni.com

Основы программирования на языке Си (стр. 10 из 27)

класса "поток". Поэтому изучение потоков полезно и по той причине, что позволяет

ознакомиться с элементами синтаксиса и некоторыми объектно-ориентированными

понятиями Си++.

Список функций для работы с файловыми потоками хранится в заголовочном

файле "fstream.h". Поэтому во всех рассматриваемых ниже фрагментах программ

предполагается, что в начале программы есть соответствующая директива "#include":

#include<fstream.h>

2.1 Создание потоков

В программе перед первым обращением к потоку ввода или вывода необходи-

мо "создать" поток. Операторы для создания потоков похожи на описания перемен-

42

ных, и они обычно размещаются в начале программы или функции рядом с описа-

ниями переменных. Например, операторы

ifstream in_stream;

ofstream out_stream;

создают поток с именем "in_stream", являющийся объектом класса (как типа данных)

"ifstream" (input-file-stream, файловый поток ввода), и поток с именем "out_stream",

являющийся объектом класса "ofstream" (output-file-stream, файловый поток вывода).

Аналогию между потоками и обычными переменными (типа "int", "char" и т.д.) не

следует понимать слишком буквально. Например, к потокам нельзя применять опера-

тор присваивания (например, нельзя записать "in_stream1 = in_stream2").

2.2 Подключение и отключение потоков от файлов

После создания потока его можно подключить к файлу (открыть файл) с помо-

щью функции-члена "open(...)". (В предыдущих лекциях уже использовались несколь-

ко функций-членов потоков вывода. Например, во 2-й лекции применялись

"precision(...)" и "width(...)".) Функция "open(...)" у потоков ifstream и ofstream работает

по-разному (т.е. это полиморфная функция).

Для подключения потока ifstream с именем "in_stream" к файлу с именем

"Lecture_4.txt" надо применить следующий вызов:

in_stream.open("Lecture_4.txt");

Этот оператор подключит поток "in_stream" к началу файла "Lecture_4.txt"

(графически состояние программы после выполнения оператора показано на рис. 2).

Рис. 2. Состояние программы после подключения потока ввода к файлу.

Чтобы к файлу "Lecture_4.txt" подключить поток вывода ofstream с именем

"out_stream", надо выполнить аналогичный оператор:

out_stream.open("Lecture_4.txt");

Этот оператор подключит поток "out_stream" к файлу "Lecture_4.txt", но при

этом прежнее содержимое файла будет удалено. Файл будет подготовлен к приему

новых данных (рис. 3).

Рис. 3. Состояние программы после подключения потока вывода к файлу.

Для отключения потока "in_stream" от файла, к которому он подключен (для

закрытия файла), надо вызвать функцию-член "close()":

43

in_stream.close();

После этого состояние программы по отношению к файлу будет таким, как на

рис. 4.

Рис. 4. Состояние программы после отключения потока ввода от файла.

Функция-член отключения от файла у потока вывода:

out_stream.close();

выполняет аналогичные действия, но, дополнительно, в конец файла добавляется

служебный символ "end-of-file (маркер конца файла)". Т.о., даже если в поток вывода

не записывались никакие данных, то после отключения потока "out_stream" в файле

"Lecture_4.txt" будет один служебный символ (рис. 5). В таком случае файл

"Lecture_4.txt" останется на диске, но он будет пустым.

Рис. 5. Состояние программы после отключения потока вывода от файла, в

который не было записано ни одного символа..

3. Проверка ошибок выполнения файловых операций

Файловые операции, например, открытие и закрытие файлов, известны как

один из наиболее вероятных источников ошибок. В надежных коммерческих про-

граммах всегда выполняется проверка, успешно или нет завершилась файловая опе-

рация. В случае ошибки вызывается специальная функция-обработчик ошибки.

Простейший способ проверки ошибок файловых операций заключается в вызо-

ве функции-члена "fail()". Вызов

in_stream.fail();

возвращает истинное значение (True), если последняя операция потока "in_stream"

привела к ошибке (может быть, была попытка открытия несуществующего файла).

После ошибки поток "in_stream" может быть поврежден, поэтому лучше не продол-

жать работу с ним.

В приведенном ниже фрагменте программы в случае ошибки при открытии

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

лиотечной функции "exit()" (она описана в файле "stdlib.h"):

#include <iostream.h>

#include <fstream.h>

#include <stdlib.h>

int main()

{

44

ifstream in_stream;

in_stream.open( "Lecture_4.txt" );

if ( in_stream.fail() )

{

cout << "Извините, открыть файл не удалось!&bsol;n";

exit(1);

}

...

4. Символьный ввод/вывод

4.1 Функция ввода "get(...)"

После того, как файл для ввода данных открыт, из него можно считывать от-

дельные символы. Для этого служит функция "get(...)". У нее есть параметр типа

"char&". Если программа находится в состоянии, как на рис. 2, то после вызова:

in_stream.get(ch);

произойдет следующее: (а) переменной "ch" будет присвоено значение "'Л'", и (б) по-

ток "in_stream" будет подготовлен для чтения следующего символа (рис. 6).

Рис. 6. Состояние программы после чтения из файла первого символа.

4.2 Функция вывода "put(...)"

С помощью потока вывода класса ofstream в открытый файл можно записы-

вать отдельные символы. Для этого у класса ofstream есть функция-член "put(...)".

Записываемый символ передается ей как параметр типа "char". Если программа пре-

бывает в состоянии, представленном на рис. 3, то оператор

out_stream.put('Л');

изменит состояние на то, которое показано на рис. 7:

Рис. 7. Состояние программы после записи в файл первого символа.

4.3 Функция "putback(...)"

В Си++ у потока ifstream есть функция-член "putback(...)". На самом деле

она не "возвращает символ назад" (т.е. не изменяет содержимого файла ввода), но ве-

дет себя так, как будто это делает. На рис. 8 показано состояние, в которое перейдет

программа из состояния рис. 6 после выполнения оператора:

45

in_stream.putback(ch);

Рис. 8. Состояние программы после вызова функции "putback('Л')".

"Вернуть назад" можно любой символ. Состояние программы после вызова

in_stream.putback('7');

показано на рис. 9.

Рис. 9. Состояние программы после вызова функции "putback('7')".

5. Проверка достижения конца файла при операциях ввода

5.1 Проверка конца файла с помощью функции "eof()"

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

достижения конца файла. В большинстве реализаций Си++ (в том числе и в Microsoft

Visual C++) в класс "поток ввода" встроен флаг "конец файла (end-of-file, EOF)" и

функция-член "eof()" для чтения этого флага. С помощью функции "eof()" можно

узнать, находится ли в данный момент флаг в состоянии True (конец файла достиг-

нут) или False (конца файла пока нет).

При открытии файла, когда поток ifstream только подключается к нему, флаг

EOF сбрасывается в значение False (даже если файл пуст). Но, если ifstream

"in_stream" сейчас расположен в конце файла, и флаг EOF равен False, то после вы-

зова

in_stream.get(ch);

переменная "ch" окажется в неопределенном состоянии, а флагу EOF будет присвоено

значение True. Если флаг EOF равен True, то программа не должна пытаться выпол-

нить чтение из файла, поскольку результат чтения будет неопределенным.

Допустим, программа находится с состоянии, показанном на рис. 10.

46

Рис. 10. Состояние программы после чтения предпоследнего символа из файла.