Смекни!
smekni.com

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

Тогда после выполнения оператора

in_stream.get(ch);

программа перейдет в состояние, изображенное на рис. 11.

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

Теперь логическое выражение

in_stream.eof()

будет иметь истинное значение True. Если снова выполнить чтение символа:

in_stream.get(ch);

то в результате получится состояние, показанное на рис. 12.

Рис. 12. Состояние программы после операции чтения символа при установ-

ленном флаге EOF.

Ниже приведена простая программа для копирования текстового файла

"Lecture_4.txt" одновременно и на экран, и в другой файл "Copy_of_4.txt". Для

прекращения копирования применяется вызов функции "eof()". Обратите внимание

на цикл "while". Цикл с префиксным условием (предусловием) "while" является уп-

рощенным вариантом цикла "for". У цикла "while" в круглых скобках "()" нет опе-

раторов инициализации и изменения значений (подробно эти циклы рассматриваются

в следующей лекции).

#include <iostream.h>

#include <fstream.h>

int main()

{

char character;

ifstream in_stream;

ofstream out_stream;

47

in_stream.open( "Lecture_4.txt" );

out_stream.open( "Copy_of_4.txt" );

in_stream.get( character );

while ( !in_stream.eof() )

{

cout << character;

out_stream.put(character);

in_stream.get(character);

}

out_stream.close();

in_stream.close();

return 0;

}

Программа 5.1.

6. Передача потоков функциям в качестве параметров

Потоки можно использовать в качестве параметров функций, но их обязатель-

но надо передавать по ссылке (а не по значению). Ниже приведен усовершенствован-

ный вариант программы 5.1, в котором копирование выполняется специальной функ-

цией "copy_to(...)".

#include <iostream.h>

#include <fstream.h>

void copy_to( ifstream& in, ofstream& out );

// Главная функция

int main()

{

ifstream in_stream;

ofstream out_stream;

in_stream.open( "Lecture_4.txt" );

out_stream.open( "Copy_of_4.txt" );

copy_to( in_stream, out_stream );

out_stream.close();

in_stream.close();

return 0;

}

// Конец главной функции

// Функция для копирования файла в другой файл и на экран

void copy_to( ifstream& in, ofstream& out )

{

char character;

in.get( character );

while ( !in.eof() )

{

cout << character;

out.put( character );

48

in.get( character );

}

}

// Конец функции

Программа 6.1.

7. Операторы ввода/вывода ">>" и "<<"

До сих пор рассматривались способы записи и чтения из файлов отдельных

символов. На нижнем уровне, скрытом внутри классов ofstream and ifstream, объ-

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

Поэтому данные других типов ("int", "double" и др.) для записи в файл должны быть

преобразованы в последовательность символов. При чтении из файла эти последова-

тельности должны быть преобразованы обратно.

Некоторые преобразования типов данных автоматически выполняются опера-

торами ">>" и "<<" (в предыдущих лекциях они часто использовались для ввода с кла-

виатуры и вывода на экран). Например, из состояния, показанного на рис. 13:

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

чения потока вывода к файлу).

с помощью оператора

out_stream << 437 << ' ';

программа перейдет в новое состояние, изображенное на рис. 14.

Рис. 14. Состояние программы после записи в поток вывода целого значения

"437" и пробела.

При использовании операторов ">>" и "<<" обязательно надо после каждого за-

писанного значения записывать еще как минимум один символ ' ' (пробел) или слу-

жебный символ '&bsol;n' (маркер конца строки). Это гарантирует, что элементы данных

будут корректно отделены в файле друг от друга, и их можно будет извлекать оттуда

с помощью оператора ">>". Например, в состоянии, показанном на рис. 15:

49

Рис. 15. Состояние программы в некоторый момент времени, когда текущая

позиция потока ввода установлена на пробел.

если "n" является переменной типа "int" и имеет значение 10, то выполнение опера-

тора

in_stream >> n;

приведет к состоянию, показанному на рис. 16.

Рис. 16. Состояние программы после чтения из потока ввода целого значения

"437".

Обратите внимание, что оператор ">>" перед числом 437 пропустил пробел ' '.

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

(даже при чтении символов).

Работа с операторами ">>" и "<<" продемонстрирована в программе 7.1. Снача-

ла она создает файл "Integers.txt", записывает в него целые числа 51, 52, 53, 54 и

55, а затем считывает эти числа из файла.

#include <iostream.h>

#include <fstream.h>

int main()

{

char character;

int number = 51;

int count = 0;

ofstream out_stream;

ifstream in_stream1; // Поток для подсчета целых чисел.

ifstream in_stream2; // Поток для подсчета символов.

// Создание файла

out_stream.open( "Integers.txt" );

for ( count = 1; count <= 5; count++ )

out_stream << number++ << ' ';

out_stream.close();

// Подсчет количества целых чисел в файле

in_stream1.open( "Integers.txt" );

count = 0;

in_stream1 >> number;

while ( !in_stream1.eof() )

{

50

count++;

in_stream1 >> number;

}

in_stream1.close();

cout << "В файле хранится " << count << " целых чисел,&bsol;n";

// Подсчет количества символов, не являющихся разделителями

in_stream2.open( "Integers.txt" );

count = 0;

in_stream2 >> character;

while ( !in_stream2.eof() )

{

count++;

in_stream2 >> character;

}

in_stream2.close();

cout << "представленных с помощью " << count << " символов.&bsol;n";

return 0;

}

Программа 7.1.

Программа 7.1 выведет на экран следующие сообщения:

В файле хранится 5 целых чисел,

представленных с помощью 10 символов.

При подсчете символов в последней части программы 7.1 снова обратите вни-

мание на то, что, в отличие от функции "get(...)", оператор ">>" игнорирует в файле

пробелы (которые разделяют пять целых чисел).

8. Сводка результатов

В лекции рассмотрены способы работы с текстовыми файлами с помощью по-

токов ввода/вывода. "Низкоуровневый" ввод/вывод выполняется с помощью функций

"get(...)" и "put(...)", а "высокоуровневый" ввод/вывод значений разных типов с

помощью потоковых операторов ">>" и "<<".

9. Упражнения

Упражнение 1

Напишите программу, печатающую на экране содержимое собственного ис-

ходного файла на Си++.

Упражнение 2

Разработайте программу, которая (1) начинается с оператора вывода тестового

сообщения:

cout << "Проверка: " << 16/2 << " = " << 4*2 << ".&bsol;n&bsol;n";

и затем (2) копирует собственный исходный файл на Си++ в файл

"WithoutComments.cpp" и на экран, при этом пропуская все комментарии между

маркерами "/* ... */" (и маркеры комментариев тоже).

51

Получившийся файл "WithoutComments.cpp" должен компилироваться и ра-

ботать точно так же, как и исходная программа.

Подсказки: (1) вам может пригодиться функция "putback()"; (2) для отслежива-

ния состояния, находитесь ли вы внутри комментария или нет, можете применить

логический "флаг".

Упражнение 3

Напишите программу, которая подсчитывает и выводит на экран количество

символов (включая пробелы) в собственном исходном файле.

Упражнение 4

Без использования массива (массивы будут рассмотрены в 6-й лекции) напи-

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

порядке.

Подсказки: (1) Для начальной части этой программы может пригодиться програм-

ма из упражнения 3. (2) Будьте внимательны и не используйте поток ввода после

ошибки – вместо этого работайте с новым потоком.

Примечание: не беспокойтесь, если перед началом печати происходит небольшая

задержка – открытие и закрытие файлов требует некоторого времени.

Упражнение 5

Что выведет на экран следующая программа?