
- •220300 - Системы автоматизированного проектирования
- •Состав языка и принцип работы компилятора языка высокого уровня
- •Идентификаторы
- •Альтернативный ввод-вывод в стиле с
- •Константы
- •Манипуляторы
- •Преобразования типов
- •Арифметические операции
- •Функции стандартной библиотеки
- •Операции отношения и логические операции
- •Базовые конструкции структурного программирования
- •Цикл с параметром (for)
- •Цикл с предусловием (while)
- •Цикл с постусловием (do while)
- •Рекомендации по программированию циклов
- •Ветвления
- •Условный оператор if
- •Вложенные конструкции
- •Проблемы соответствия if и else во вложенных ветвлениях
- •Условная операция
- •Оператор switch
- •Операторы передачи управления
- •Контрольная работа
- •Массивы
- •Сортировка массива методом выбора
- •Сортировка массива методом пузырька
- •Многомерные массивы
- •Операции со строками
- •Функции
- •Void starline(); // объявление функции (прототип)
- •Передача аргументов в функцию по значению
- •Void charline(char sim, int n); // объявление функции (прототип)
- •Возвращение функцией значения
- •Передача аргументов по ссылке
- •Возвращение значения по ссылке
- •Перегруженные функции
- •Переменные и функции
- •Передача массивов в функции
- •Указатели
- •Указатели и массивы
- •Указатели и функции
- •Указатели и строки
- •Динамический массив и динамическое выделение памяти
- •Ввод/вывод
- •Форматированный ввод/вывод
- •Конструкторы и методы
- •Двоичный ввод/вывод. Бинарные файлы
- •Двунаправленный ввод/вывод
- •Функции стандартной библиотеки для работы с файлами или ввод/вывод в стиле с
Двунаправленный ввод/вывод
До сих пор мы рассматривали программы, в которых использовали только ifstream – класс входных файловых потоков (для чтения файла) и ofstream – класс выходных файловых потоков (для записи в файл). Хотя, как уже раннее говорилось, существует ещё fstream – класс двунаправленных файловых потоков. Двунаправленный файловый поток обеспечивает возможность считывать данные из файла и записывать данные в файл, ограничиваясь всего одним потоком и объектом. Использование класса двунаправленных файловых потоков освобождает нас от необходимости создания файловых объектов, предназначенных либо для ввода, либо для вывода. Таким образом, с помощью объекта класса fstream можно создать поток к файлу, который может быть использован как входной и выходной.
Создавать двунаправленные файловые потоки имеет смысл в том случае, когда в одной программе необходимо обеспечивать как считывание данных из файла, так и запись данных. Причём ввод/вывод может происходить хаотично или вследствие определённых событий или действий пользователя. Приведём пример, демонстрирующий создание двунаправленного файлового потока.
…
fstream file;
file.open("имя_файла", ios::out | ios::in | ios::binary);
…
file.write(…);
…
file.read(…);
…
Здесь, с помощью объекта file можно осуществлять как считывание данных из файла, так и запись данных в этот файл.
Функции стандартной библиотеки для работы с файлами или ввод/вывод в стиле с
Ввод/вывод в стиле С удобнее использовать при форматированном выводе в программах, не использующих объектно-ориентированную технологию. Представление о вводе/выводе в стиле С необходимо иметь по причине существования множества программ, написанных на С, с которыми программисту поневоле приходится сталкиваться.
Для использования функций ввода/вывода в стиле С необходимо подключать к программе заголовочный файл <stdio.h> или <cstdio>. Практически также как в случае с потоковыми классами С++, при вводе/выводе в стиле С данные рассматриваются как поток байтов. Работа с потоком начинается с его открытия. Поток можно открыть для чтения и/или записи в двоичном или текстовом режиме.
Функция открытия потока имеет формат: FILE* fopen(const char* имя_файла, const char* режим);. При неудачном открытии потока функция возвращает NULL. Первый параметр – имя открываемого файла в виде С-строки, второй – режим открытия файла:
"r" – файл открывается для чтения;
"w" – открывается пустой файл для записи (если файл существует, он стирается);
"а" – файл открывается для добавления информации в его конец;
"r+" – открыть для чтения и записи (файл должен существовать);
"w+" – открыть пустой файл для чтения и записи (если файл существует, он стирается);
"a+" – файл открывается для чтения и добавления информации в его конец.
Режим открытия может также содержать символы t (текстовый режим) или b (двоичный режим). По умолчанию файл открывается в текстовом режиме. Приведём пример открытия бинарного файла для чтения:
FILE *f=fopen("c:\\data", "rb+");
Здесь, указатель f используется для дальнейших операций с потоком. Его передают функциям ввода/вывода в качестве параметра.
Ввод/вывод в поток можно осуществлять различными способами: в виде последовательности байтов, в виде символов и строк или с использованием форматных преобразований. Операции ввода/вывода выполняются начиная с текущей позиции потока, определяемой положением указателя потока. Текущее положение указателя можно получить с помощью функций ftell и fgetpos и задать явным образом с помощью функций fseek и fsetpos.
Чтение и запись потока байтов выполняют функции fread и fwrite; чтение символа из потока – getc, fgetc; запись символа в поток – putc, fputc; чтение строки из потока – fgets; запись строки в поток – fputs; форматированный ввод из потока – fscanf; форматированный вывод в поток – fprintf; закрытие потока явным образом – fclose.
Приведём пример программы на языке С, которая создаёт файл numbers.txt и записывает в него 5 введённых пользователем целых чисел.
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
using namespace std;
int main() {
const int K=5; //кол-во чисел
int n;
char fname[] = "c:\\os\\numbers.txt";
FILE *fout;
if((fout=fopen(fname, "wt"))==NULL) { //если при открытии текст. файла произ. ошибка
cout << "\nOshibka otkrytiya faila dlya zapisi!";
getch(); return 1;
}
for(int i=0; i<K; i++) {
cout << "Vvedite " << i+1 << "-e chislo: "; cin >> n;
fprintf(fout, "%i", n); //запись введённого числа в файл
fputc(' ', fout);
}
cout << "\n Chisla zapisany v fail!";
fclose(fout); //закрыть файловый поток
getch(); return 0;
}
А теперь рассмотрим программу, позволяющую считывать данные из созданного файла numbers.txt и вычислять среднее арифметическое значение считанных чисел.
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
using namespace std;
int main() {
int n, k=0, sum=0; //число, кол-во чисел, сумма чисел
float sr;
char fname[] = "c:\\os\\numbers.txt";
FILE *fin;
if((fin=fopen(fname, "rt"))==NULL) {
cout << "\nOshibka otkrytiya faila dlya zapisi!";
getch(); return 1;
}
cout << "Fail sodergit: ";
while(!feof(fin)) { //пока не конец файла
fscanf(fin, "%i", &n); //считать число
cout << " " << n;
sum = sum + n;
k++;
} //в файле после последней цифры не должно быть пробела
fclose(fin);
sr=(float)sum/n;
cout << "\nSumma chisel = " << sum;
cout << "\nSrednee arifm. = " << sr;
getch(); return 0;
}
В заключение хотел бы ещё раз отметить, что при работе с файлами лучше стараться применять потоковые классы С++, которые обеспечивают более надёжную работу как со стандартными, так и с определёнными пользователем типами данных, а также единообразный и понятный синтаксис.