Смекни!
smekni.com

Основы алгоритмического языка С++ (стр. 19 из 21)

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

Существуют некоторые особые тонкости, связанные с файлами текстовогорежима, на которые следует обратить особое внимание и запомнить. Перваяиз них - символ EOF (26 в коде ASCII или Ctrl+Z) - представляет собой метку(символ) конца файла. В текстовом режиме, где встречается символ EOF,система C++ низкого уровня автоматически продвигается к концу файла;вы ничего не можете прочитать после специального символа. Это может вызватьпроблемы, если такой специальный символ окажется в середине файла.

Другая особенность текстового режима заключается в том, какинтерпретируются строки текстового файла. Каждая строка заканчиваетсяпоследовательностью конца строки (EOL). На компьютерах PC и совместимых сними EOL-последовательность представлена двумя символами кода ASCII:CR (13 в коде ASCII или Ctrl+M) и LF (10 в коде ASCII или Ctrl+J).Эта CRLF-последовательность используется функциями чтения и записи текстовойстроки, которые автоматически, вставляют ее в файл или удаляют из него.Заметьте, что на большинстве других, систем (UNIX и Macintosh) EOF простоявляется символом LF.

Функция-компонент open

Прототип функции open

void open (const char* filename, int mode, int m = filebuf::openprot);

Параметр filename задает имя открываемого файла. Параметр mode указываетрежим ввода/вывода. Далее следует список аргументов для mode, описанных взаголовочном файле FSTREAM.H:

inоткрыть поток для ввода,

outоткрыть поток для вывода,

ateустановить указатель потока на конец файла,

app открыть поток для добавления,

trunk удалить содержимое файла, если он уже существует (bc++5),

nocreate инициировать ошибку, если уже не существует,

noreplace инициировать ошибку, если файл уже существует,

binary открыть в двоичном режиме.

Пример 1.

// открыть поток для ввода

fstream f;

f.open("simple.txt", ios::in);

// открыть поток для вывода fstream f;

fstream f;

f.open ("simple.txt", ios::out);

// открыть поток ввода/вывода для двоичных данных fstream f;

fstream f;

f.open("simple.txt", ios::in | ios::out | ios::binary);

Внимание: Классы файловых потоков предусматривают конструкторы, которыевыполняют действия (и имеют такие же параметры) функции-компонента open.

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

Функция-компонент close

Прототип для функции close:

void close();

Пример 2.

fstream f;

// открыть поток

f.open ( "simple.txt", ios:: in);

// работа с файлом

// закрыть поток

f.close ();

Stream-библиотека C++ включает в себя набор основных функций, которыеконтролируют состояние ошибки потоковой операции. Эти функции включаютследующие:

Функция good() возвращает ненулевое значение, если при выполнениипотоковой операции не возникает ошибки. Объявление функции good:int good();

Функция fail() возвращает ненулевое значение, если при выполнениипотоковой операции возникает ошибка. Объявление функции fail:int fail();

Перегруженная операция ! применяется к экземпляру потока для определения состояния ошибки.

Stream-библиотека C++ предоставляет дополнительные функции дляустановки и опроса других аспектов и типов ошибок потока.

ПОСЛЕДОВАТЕЛЬНЫЙ ТЕКСТОВЫЙ ПОТОК ВВОДА/ВЫВОДА

Функции и операции последовательного текстового ввода/вывода являютсядовольно простыми. Вы уже имели дело со многими из них в предыдущихуроках. Эти функции и операции включают:

Операция извлечения из потока << записывает строки или символы в поток.

Операция помещения в поток >> читает символы потока.

Функция getline читает строку из потока.

Функция-элемент getline

Прототипы функции-элемента getline:

istream& getline (char* buffer, int size, char delimiter = '&bsol;n');

istream& getline (signed char* buffer, int size, char delimiter = '&bsol;n');

istream& getline (unsigned char* buffer, int size, char delimiter = '&bsol;n');

Параметр buffer - это указатель на строку, принимающую символы из потока.Параметр size задает максимальное число символов для чтения. Параметрdelimiter указывает разделяющий символ, который вызывает прекращение вводастроки до того, как будет введено количество символов, указанное в параметреsize. По умолчанию параметру delimiter присваивается значение '&bsol;n'.

Пример 3.

fstream f;

char textLine[MAX];

f.open("sample.txt", ios::in);

while (!f.eof()){

f.getline(textLine, MAX);

cout << textLine << endl;

}

f.close();

Рассмотрим пример. В листинге 10.1 приведен исходный код программыTRIM.CPP. Программа выполняет следующие задачи:

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

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

Читает строки из входного файла и удаляет из них <висящие> пробелы.

Записывает эти строки в выходной файл и также в стандартное окно вывода.

Листинг 10.1. Исходный код программы TRIM.CPP

// C++ программа демонстрации последовательного файлового

// ввода/вывода

Программа в листинге 10.1 не объявляет никаких классов, вместо этого онафокусируется на использовании файловых потоков для ввода и вывода текста. Этапрограмма описывает функции trimStr, getInputFilename, getOutputFilename,processLines и обязательную функцию main.

Функция trimStr вычищает <висящие> пробелы в строках, передаваемых черезпараметр s. Эта функция объявляет переменную i и присваивает ей индекссимвола, находящегося сразу за завершающим нулем. Функция использует циклwhile, начинающийся в строке 14, чтобы выполнить обратное сканированиесимволов в строке s до первого символа, не являющегося пробелом. Оператор встроке 16 присваивает завершающий нуль символу, стоящему справа отпоследнего символа, не являющегося пробелом, в строке s.

Функция getInputFilename получает имя входного файла и открываетсоответствующий файловый поток. Параметр inFile передает это имя вызывающейфункции. Ссылочный параметр f передает открытый входной поток вызывающейфункции. Функция getInputFilename объявляет локальный флажок ok и используетцикл do-while (строки с 23 по 34), чтобы открыть входной файл. Строка 25содержит первый оператор тела цикла, в котором флажок ok инициализируетсязначением true. Оператор вывода в строке 26 запрашивает ввод имени входногофайла; в строке 27 с помощью вызова функции getline это имя принимается исохраняется в переменной inFile. Оператор в строке 28 пытается открытьвходной файл, используя параметр потока f. Оператор open использует значениеios::in для указания на то, что входной текстовый файл был открыт. Если вызоввозвращает ошибку, оператор if (строка 29) определит это, сообщит об ошибкеоткрытия файла пользователю и присвоит переменной ok значение false. Призначении ok, равном true, цикл do-while будет выполняться и сохранять ответыпользователя до тех, пока не произойдет успешное открытие файла.

Функция getOutputFilename подобна функции getInputFilename в попыткахполучить имя файла от пользователя и открыть файл. Однако в этом случае файлоткрывается на запись и его имя сравнивается с именем входного файла. Встроке 47 проверяется совпадение имен входного и выходного файлов, и, еслипользователь ввел одно и то же имя, ему предлагается снова ввести имявыходного файла.

Функция processLines читает строки их входного файлового потока, приводяих в порядок и записывая в выходной файловый поток. Параметры fin и fontпередают файловые указатели входного и выходного потоков, соответственно.Эта функция объявляет локальную строковую переменную line и использует(строки с 69 по 74) цикл while для обработки текстовых строк. Предложениеwhile содержит вызов функции getline, которая читает следующую строкувходного потока fin и присваивает переменной line содержимое этой строки. Втеле этого цикла просто вызывается функция trimStr, а затем line передаетсяв потоки fout и cout. Заметьте, что команды для получения строки текста изфайла и передачи ее в файл в точности совпадают с теми, которые могли быиспользоваться для получения текста с экрана и передачи его на экран. Этопроисходит потому, что используемые вами cout и cin - на самом деле толькопотоки, которые открываются автоматически и работают непосредственно с экраном.

Функция main, как обычно со всеми уже описанными функциями, довольнопростая. Она только объявляет переменные файловых потоков fin, fout и inFile,outFile для сохранения имен этих потоков. Далее входной и выходной файлыоткрываются в функциях getInputFilename и getOutputFilename. Наконец, функцияprocessLine приводит в порядок и копирует содержимое файла, а функция-компонент close вызывается для каждого из потоков.

ПОСЛЕДОВАТЕЛЬНЫЙ ДВОИЧНЫЙ ФАЙЛОВЫЙ ВВОД/ВЫВОД

Stream-библиотека C++ имеет перегруженные потоковые функции-элементыwrite и read для последовательного двоичного файлового ввода/вывода.Функция write посылает ряд байт в выходной поток. Эта функция можетзаписывать любую переменную или экземпляр в поток.

Функция-элемент write

Прототип перегруженной функции-элемента:

ostream& write(const char* buff, int num);

ostream& write(const signed char* buff, int num);

ostream& write(const unsigned char* buff, int num);

Параметр buff - это указатель на буфер, содержащий данные, которые будутпосылаться в выходной поток. Параметр num указывает число байт в буфере,которые передаются в этот поток.

Пример 4.

const MAX = 80;

char buff[MAX+1] = "Hello World!";

int len = strlen (buff) + 1;

fstream f;

f.open("CALC.DAT", ios::out | ios::binary);

f.write((const unsigned char*) &len, sizeof(len));

f.write((const unsigned char*) buff, len);

f.close();

В этом примере открывается файл CALC.DAT, записывается целое, содержащеечисло байт в строке и записывается сама строка перед тем, как файлзакрывается.

Функция read считывает некоторое количество байт из входного потока. Этафункция может считывать любую переменную или экземпляр из потока.