Для управления вводом-выводом в C++ используются:
Флаги позволяют включить или выключить один из параметров вывода на экран. Для установки флага вывода используется следующая конструкция языка C++:
cout.setf(ios::flag)
Для снятия флага применяют конструкцию
cout.unsetf(ios::flag)
здесь flag — имя конкретного флага.
Если при выводе необходимо установить несколько флагов, то можно воспользоваться арифметической операцией "или" (|). В этом случае конструкция языка C++ будет такой:
cout.setf(ios::flag1|ios::flag2|ios::flag3)
В данном случае flag1, flag2, flag3 — имена устанавливаемых флагов вывода.
В табл. 7.1 приведены некоторые флаги форматного вывода с примерами их использования.
| Флаг | Описание | cout.width(n) устанавливает ширину поля вывода, подробнее об этом в п. 7.1.2 |
Результат |
|---|---|---|---|
right |
Выравнивание по правой границе | int r=-25; cout. setf ( ios :: right ); cout.width(15); cout<<"r="<<r<<endl; |
r=-25 |
left |
Выравнивание по левой границе (по умолчанию) | double r=-25.45; cout. setf ( ios :: left ); cout.width(50); cout<<"r="<<r<<endl; |
r=-25.45 |
boolalpha |
Вывод логических величин в текстовом виде (true, false) |
bool a=true; cout<<a<<endl; cout. setf ( ios :: boolalpha); cout<<a<<endl; |
true |
dec |
Вывод величин в десятичной системе счисления (по умолчанию) | int r=-25; cout<<"r="<<r<<endl; |
r=-25 |
oct |
Вывод величин в восьмеричной системе счисления | int p=23; //Отменить, установленный по умолчанию, вывод в десятичной системе счисления cout.unsetf( ios :: dec); //Установить вывод в восьмеричной системе счисления cout. setf ( ios :: oct); cout<<"p="<<p<<endl; |
p=27 |
hex |
Вывод величин в шестнадцатеричной системе счисления | int p=23; //Отменить, установленный по умолчанию, вывод в десятичной системе счисления cout.unsetf( ios :: dec); //Установить вывод в шестнадцатеричной системе счисления cout. setf ( ios :: hex); cout<<"p="<<p<<endl; |
p=17 |
showbase |
Выводить индикатор основания системы счисления | int p=23; cout.unsetf( ios :: dec); cout. setf ( ios :: hex| ios :: showbase); cout<<"p="<<p<<endl; |
p=0x17 |
uppercase |
Использовать прописные буквы в шестнадцатеричных цифрах | int p=29; cout.unsetf( ios :: dec); cout. setf ( ios :: hex| ios :: uppercase); cout<<"p="<<p<<endl; |
p=1D |
showpos |
Выводить знак "+" для положительных чисел | int p=29; cout. setf ( ios :: showpos); cout<<"p="<<p<<endl; |
p=+29 |
scientific |
Экспоненциальная форма вывода вещественных чисел | double p=146.673; cout. setf ( ios :: scientific ); cout<<"p="<<p<<endl; |
p=1.466730e+002 |
fixed |
Фиксированная форма вывода вещественных чисел (по умолчанию) | double p=146.673; cout. setf ( ios :: fixed ); cout<<"p="<<p<<endl; |
p=146.673 |
Флаги удобно использовать в тех случаях, когда следует изменить параметры всех последующих операторов ввода-вывода. Использование большого количества флагов для управления одним или несколькими операторами ввода-вывода не совсем удобно, потом все установленные флаги придётся отключать.
Ещё одним способом форматирования является использование манипуляторов непосредственно в конструкциях cin и cout.
Манипуляторы встраиваются непосредственно в операторы ввода-вывода. C одним из манипуляторов ($$endl$$) читатель уже встречался начиная с первой главы книги. В табл. 7.2 приведены основные манипуляторы форматирования с примерами их использования. Для корректного использования всех манипуляторов необходимо подключить библиотеку:
#include <iomanip>
| Манипулятор | Манипулятор | Пример использования | Результат |
|---|---|---|---|
setw(n) |
Определяет ширину поля вывода в n символов | int r=253; cout. setf ( ios :: fixed ); cout<<"r="<<setw(8)<<r<<endl; |
r= 253 |
setprecision(n) |
Определяет количество цифр $$(n - 1)$$ в дробной части числа | double h=1234.6578; cout. setf ( ios :: fixed ); cout<<"h="<<setw(15); cout<<setprecision(3); cout<<h<<endl; |
h=1234.658 |
dec |
Перевод числа в десятичную систему (по умолчанию) | int r=0253; cout<<"r="<<dec<<r<<endl; |
; r=171 |
oct |
Перевод числа в восьмеричную систему | int r=253; cout<<"r="<<oct<<r<<endl; |
r=375 |
hex |
Перевод числа в шестнадцатеричную систему | int r=253; cout<<"r="<<hex<<r<<endl |
p=fd |
right |
Выравнивание по правой границе | int r=-25; cout.width(15); cout<<"r="<<setw(15)<<right; cout<<r<<endl; |
r=-25 |
left |
Выравнивание по левой границе (по умолчанию) | int r=-25; cout.width(15); cout<<"r="<<setw(15)<<left; cout<<r<<endl; setfill |
r=-25 |
boolalpha |
Вывод логических величин в текстовом виде (true, false) |
bool a=true; cout<<boolalpha<<a<<endl; |
true |
noboolalpha |
Вывод логических величин в числовом виде (1, 0) | bool a=true; cout<<noboolalpha<<a<<endl; |
1 |
showpos |
Выводить знак "+" для положительных чисел | int p=29; cout<<"p="<<showpos<<p<< endl; |
p=+29 |
noshowpos |
Не выводить знак "+" для положительных чисел | int p=29; cout<<"p="<< noshowpos<<p<<endl; |
p=29 |
uppercase |
Использовать прописные буквы в шестнадцатеричных цифрах | int p=253; cout<<"p="<<hex<< uppercase<<p<<endl; |
p=FD |
nouppercase |
Использовать строчные буквы в шестнадцатеричных цифрах | int p=253; cout<<"p="<<hex<<nouppercase; cout<<p<<endl; |
p=fd |
showbase |
Выводить индикатор основания системы счисления | int p=253; cout<<"p="<<hex<<uppercase <<showbase<<p<<endl; |
p=0XFD |
noshowbase |
Не выводить индикатор основания системы счисления | int p=253; cout<<"p="<<hex<<uppercase; cout<<noshowbase<<p<<endl; |
p=FD |
setfill(c) |
Установить символ с как заполнитель | cout<<"x="<<right<<
setw(10)<<setprecision(4);
cout<<setfill("!");
cout<<(float)1/7<<endl;
cout<<"x="<<left<<setw(10);
cout<<setprecision(4);
cout<<setfill("!");
cout<<(float)1/7<<endl; |
x=!!!!0.1429 x=0.1429!!!! |
scientific |
Экспоненциальная форма вывода вещественных чисел | double p=146.673; cout<<"p="<<scientific<<p<< endl; |
p=1.466730e+002 |
fixed |
Фиксированная форма вывода вещественных чисел (по умолчанию) | cout<<"p="<<fixed<<p<<endl; |
p=146.673 |
Кроме того, управлять шириной поля вывода можно с помощью операторов:
cout.width(n) — устанавливает ширину поля вывода — $$n$$ позиций;cout.precision(m) — определяет $$m$$ цифр в дробной части числа.В п. 7.1.1 и 7.1.2 были рассмотрены основные возможности форматированного ввода-вывода. При использовании конструкций cin и cout фактически происходит ввод-вывод в текстовый файл. При вводе текстовым файлом является клавиатура ПК, при выводе в качестве текстового файла выступает экран дисплея, cin и cout фактически являются именами
Существует два основных типа файлов: текстовые и двоичные. Файлы позволяют пользователю считывать большие объёмы данных непосредственно с диска, не вводя их с клавиатуры.
Текстовыми называют файлы, состоящие из любых символов. Они организуются по строкам, каждая из которых заканчивается символом "конец строки". Конец самого файла обозначается символом "конец файла". При записи информации в текстовый файл, просмотреть который можно с помощью любого текстового редактора, все данные преобразуются к символьному типу и хранятся в символьном виде.
Для работы с файлами используются специальные типы данных, называемые ifstream служит для работы с файлами в режиме чтения. Поток ofstream служит для работы с файлами в режиме записи. Для работы с файлами в режиме как чтения, так и записи служит поток iofstream.
В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream.
Для того, чтобы записать данные в текстовый файл, необходимо:
Для того, чтобы считать данные из текстового файла, необходимо:
Для того, чтобы начать работать с текстовым файлом, необходимо описать переменную типа ofstream. Например, с помощью оператора
ofstream, ifstream, iofstream, а термин "файл" для указания реального файла на диске.
будет создана переменная F для записи информации в файл. На следующем этапе файл необходимо открыть для записи. В общем случае оператор открытия потока будет иметь вид:
F.open("file", mode);
Здесь F — переменная, описанная как ofstream, file — имя файла на диске, mode — режим работы с открываемым файлом.
Файл может быть открыт в одном из следующих режимов:
ios::in — открыть файл в режиме чтения данных, этот режим является режимом по умолчанию для потоков ifstream;ios::out — открыть файл в режиме записи данных (при этом информация в существующем файле уничтожается), этот режим является режимом по умолчанию для потоков ofstream;ios::app — открыть файл в режиме записи данных в конец файла;ios::ate — передвинуться в конец уже открытого файла;ios::trunc — очистить файл, это же происходит в режиме ios::out;ios::noreplace — не открывать существующий файл.Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного ios::in — для потоков ifstream, ios::out — для потоков ofstream.
После удачного открытия файла (в любом режиме) в переменной F будет храниться true, в противном случае false. Это позволит проверять корректность операции открытия файла.
Открыть файл (в качестве примера возьмём файл abc.txt) в режиме записи можно одним из следующих способов:
//Первый способ. ofstream f; f.open ( " abc.txt ", ios::out ); //Второй способ, //режим ios::out является режимом по умолчанию для потока ofstream ofstream f; f.open ( " abc.txt " ) //Третий способ объединяет описание переменной типа поток //и открытие файла в одном операторе ofstream f( " abc.txt ", ios::out );
После открытия файла в режиме записи будет создан пустой файл, в который можно будет записывать информацию. Если нужно открыть файл, чтобы в него что-либо дописать, то в качестве режима следует использовать значение ios::app.
После открытия файла в режиме записи, в него можно писать точно также, как и на экран, только вместо стандартного устройства вывода cout необходимо указать имя открытого для записи файла.
Например, для записи в поток F переменной a оператор вывода будет иметь вид:
F<<a;
Для последовательного вывода в поток G переменных b, c и d оператор вывода станет таким:
G<<b<<c<<d;
Закрытие потока осуществляется с помощью оператора:
F.close();
В качестве примера рассмотрим следующую задачу.
Задача 7.1. Создать текстовый файл abc.txt и записать туда n вещественных чисел.
Текст программы с комментариями:
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main ( )
{
int i, n; double a;
ofstream f; //Описывает поток для записи данных в файл.
f.open ( " abc.txt " ); //Открываем файл в режиме записи,
//режим ios::out устанавливается по умолчанию.
cout<<" n = "; cin>>n; //Ввод количества вещественных чисел.
for ( i =0; i<n; i++)
{
cout<<" a = "; cin>>a; //Ввод очередного числа.
if ( i<n-1) //Если число не последнее,
f<<a<<" \t "; //записать в файл это число и символ табуляции, иначе
else f<<a; //записать только число.
}
f.close ( ); //Закрытие потока.
return 0;
}
Обратите внимание, что в текстовый файл записываются не только вещественные числа, но и символы табуляции. Таким образом, в конце файла после последнего числа находится символ табуляции. По этой причине может возникнуть проблема при чтении информации (п. 7.2.2), так как символ табуляции будет интерпретирован как вещественное число. Чтобы этого избежать в программе была применена следующая конструкция:
if (i<n-1) f<<a<<"\t"; else f<<a;
Здесь реализована проверка ввода последнего числа. После него символ табуляции отсутствует.
В результате работы программы будет создан текстовый файл abc.txt, который можно просмотреть средствами обычного текстового редактора (рис. 7.1,рис. 7.2).
(рис 7.1) Процесс работы программы к задаче 7.1. Ввод исходных данных.
(рис 7.2) Текстовый файл abc.txt, созданный программой к задаче 7.1.
Для того, чтобы прочитать информацию из текстового файла, необходимо описать переменную типа ifstream. После этого файл необходимо открыть для чтения с помощью оператора open. Если переменную назвать F, то первые два оператора будут такими:
ifstream F;
F.open("abc.txt", ios::in);
ios::in можно, конечно, опустить, ведь для потока ifstream значение ios::in является значением по умолчанию, тогда оператор open можно будет записать так F.open("abc.txt");
После открытия файла в режиме чтения, из него можно считывать информацию точно так же, как и с клавиатуры, только вместо стандартного устройства ввода cin необходимо указать имя потока, из которого будет происходить чтение данных.
Например, для чтения из потока F в переменную a оператор ввода будет иметь вид:
F>>a;
Для последовательного ввода из потока G в переменные b, с и d оператор ввода станет таким:
G>>b>>c>>d;
Два числа в текстовом файле считаются разделёнными, если между ними есть хотя бы один из символов: пробел, табуляция, символ конца строки.
Хорошо, если программисту заранее известно, сколько и каких значений хранится в текстовом файле. Однако часто просто известен тип значений, хранящихся в файле, при этом количество значений в файле может быть различным. При решении подобной проблемы необходимо считывать значения из файла по одному, а перед каждым считыванием проверять, достигнут ли конец файла. Для проверки, достигнут или нет конец файла, служит функция
f.eof();
Здесь F — имя потока, функция возвращает логическое значение: true — если достигнут конец файла, если не достигнут функция возвращает значение false.
Следовательно, цикл для чтения содержимого всего файла можно записать так.
while ( ! f.eof ( ) ) //Организован цикл, условием окончания цикла
//является достижение конца файла, в этом случае f.eof() вернёт true.
{
F>>a; //Чтение очередного значения из потока F в переменную a.
...
<обработка значения переменной a>
}
Рассмотрим следующую задачу.
Задача 7.2. В текстовом файле $$abc.txt$$ хранятся вещественные числа (рис. 7.2), вывести их на экран и вычислить их количество.
Текст программы с комментариями приведён ниже.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
ifstream f; //Поток для чтения.
float a; int n=0;
f.open ( " abc.txt " ); //Открываем файл в режиме чтения.
if ( f ) //Если открытие файла прошло корректно, то
{
while ( !f.eof ( ) ) //Организован цикл, выполнение цикла
//прервётся, когда будет достигнут конца файла.
{
f>>a; //Чтение очередного значения из потока f в переменную a.
cout<<a<<" \t "; //Вывод значения переменной a
n++; //Увеличение количества считанных чисел.
}
f.close ( ); //Закрытие потока.
cout<<" n = "<<n<<endl; //Вывод на экран количества чисел.
}
else cout<<"Файл не найден"<<endl; //Если открытие файла прошло некорректно, то
//вывод сообщения, об отсутствии такого файла.
return 0;
}
Результат работы программы к задаче 7.2:
3.14159 2.789 -21.14 543.89 -90.1 n=5
Программа работает корректно, если текстовый файл abc.txt был создан с помощью программы к задаче 7.1. Предположим, что файл создавался в текстовом редакторе, и пользователь ввёл после последней цифры символ пробела, табуляции или перехода на новую строку. Тогда результат будет таким:
3.14159 2.789 -21.14 543.89 -90.1 -90.1 n= 6
Происходит это потому, что после чтения последней цифры из потока конец файла не достигнут, оператор цикла выполняется ещё один раз, значение переменной $$n$$ увеличивается на единицу, а так как значение переменной $$a$$ не изменилось, то выводится повторно. Один из способов решения данной проблемы может быть таким:
while ( !f.eof ( ) )
{
f>>a;
if ( !f.eof ( ) ) //Проверяем, достигнут ли конец файла, если нет — печатаем значение a
{
cout<<a<<" \t ";
n++;
}
}
Если количество вещественных чисел, записанных в файл, известно заранее, то текст программы можно переписать следующим образом:
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
ifstream f;
float a; int i, n=5;
f.open ( " abc.txt " );
if ( f )
{
for ( i =1; i<=n; f>>a, cout<<a<<" \t ", i++);
f.close ( );
}
else cout<<"Файл не найден"<<endl;
return 0;
}
Существует возможность открывать файл с данными таким образом, чтобы в него можно было дописывать информацию. Рассмотрим эту возможность на примере решения следующей задачи.
Задача 7.3. В файле $$abc.txt$$ (рис. 7.2) хранится массив вещественных чисел, дописать в файл этот же массив, упорядочив его по возрастанию.
Алгоритм решения задачи очень простой. Считываем в массив данные из текстового файла, упорядочиваем массив, дописываем его в этот же файл.
Для чтения данных из файла описываем поток ifstream, открываем его в режиме чтения и последовательно, пока не достигнем конца файла, считываем все элементы в массив. Сортировку проведём методом пузырька. Обратите внимание, что поток нужно открыть так, чтобы была возможность дописать в конец файла упорядоченный массив.
Текст программы с комментариями приведён ниже.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
ifstream f; //Поток для чтения.
ofstream g; //Поток для записи.
float *a, b;
a=new float [ 100 ];
int i, j, n=0;
f.open ( " abc.txt ", ios::in ); //Открываем файл в режиме чтения.
if ( f )
{
while ( !f.eof ( ) )
{
f>>a [ n ];
n++;
}
//Сортировка массива.
for ( i =0; i<n-1; i++)
for ( j =0; j<n-i -1; j++)
if ( a [ j ]>a [ j +1 ])
{
b=a [ j ];
a [ j ]=a [ j + 1 ];
a [ j +1]=b;
}
f.close ( ); //Закрываем поток для чтения.
g.open ( " abc.txt ", ios::app ); //Открываем поток для того, чтобы дописать данные.
g<<" \n "; //Запись в файл символа конца строки
for ( i =0; i<n; i++) //Запись в файл
if ( i<n-1) g<<a [ i ]<< " \t "; //элемента массива и символа табуляции.
else g<<a [ i ]; //Запись последнего элемента массива
g.close ( ); //Закрытие файла.
}
else cout<<"Файл не найден"<<endl;
delete [ ] a;
return 0;
}
Содержимое файла abc.txt после запуска программы к задаче 7.3
3.14159 2.798 -21.14 543.89 -90.1 -90.1 -21.14 2.798 3.14159 543.89
Если в файле хранятся только числа или данные определённой структуры, то для хранения таких значений удобно пользоваться двоичными файлами. В двоичных файлах информация считывается и записывается в виде блоков определённого размера, в них могут храниться данные любого вида и структуры.
Порядок работы с двоичными и текстовыми файлами аналогичен. Для того, чтобы записать данные в двоичный файл, необходимо:
FILE *filename; Здесь filename — имя переменной, где будет храниться указатель на файл.fopen.fwrite.fclose.Для того, чтобы считывать данные из двоичного файла, необходимо:
FILE *.fopen.fread, при считывании информации следить за тем, достигнут ли конец файла.fclose.Рассмотрим основные функции, необходимые для работы с двоичными файлами.
Для открытия файла предназначена функция:
FILE *fopen(const *filename, const char *mode); где, filename — строка, в которой хранится полное имя открываемого файла, mode — строка, которая определяет режим работы с файлом; возможны следующие значения:
"rb" — открыть двоичный файл в режиме чтения;"wb" — создать двоичный файл для записи, если файл существует, то его содержимое очищается."ab" — создать или открыть двоичный файл для добавления информации в конец файла;"rb+" — открыть существующий двоичный файл в режиме чтения и записи;"wb+" — открыть двоичный файл в режиме чтения и записи, существующий файл очищается;"ab+" — двоичный файл открывается или создаётся для исправления существующей информации и добавления новой в конец файла.Функция fopen возвращает в файловой переменной NULL в случае неудачного открытия файла.
После открытия файла, в указателе содержится адрес 0-го байта файла. По мере чтения или записи значение указателя смещается на считанное (записанное) количество байт. Текущее значение указателя — номер байта, начиная с которого будет происходить операция чтения или записи.
Для закрытия файла предназначена функция
int fclose(FILE *filename);
Она возвращает 0 при успешном закрытии файла и NULL в противном случае.
Для удаления файлов существует функция
int remove(const char *filename);
Эта функция удаляет с диска файл с именем filename. Удаляемый файл должен быть закрыт. Функция возвращает ненулевое значение, если файл не удалось удалить.
Для переименования файлов предназначена функция
int rename(const char *oldfilename, const char *newfilename);
здесь первый параметр — старое имя файла, второй — новое. Возвращает 0 при удачном завершении программы.
Чтение из двоичного файла осуществляется с помощью функции
fread (void *ptr, size, n, FILE *filename)
Эта функция считывает из файла filename в массив ptr n элементов размера size. Функция возвращает количество считанных элементов. После чтения из файла указатель файла смещается на n*size байт.
Запись в двоичный файл осуществляется с помощью функции
fwrite (const void *ptr, size, n, FILE *filename);
Функция записывает в файл filename из массива ptr n элементов размера size. Функция возвращает количество записанных элементов. После записи информации в файл, указатель файла смещается на n*size байт.
Для контроля достижения конца файла есть функция
int feof(FILE * filename);
Она возвращает ненулевое значение, если достигнут конец файла.
Рассмотрим использование двоичных файлов на примере решения двух стандартных задач.
Задача 7.4.Создать двоичный файл $$abc.dat$$, куда записать целое число $$n$$ и $$n$$ вещественных чисел.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
FILE * f; //Описание файловой переменной.
int i, n; double a;
f=fopen ( " abc.dat ", " wb " ); //Создание двоичного файла в режиме записи.
cout<<" n = "; cin>>n; //Ввод числа n.
fwrite (n, sizeof ( int ), 1, f ); //Запись числа в двоичный файл.
for ( i =0; i<n; i++) //Цикл для ввода n вещественных чисел.
{
cout<<" a = "; cin>>a; //Ввод очередного вещественного числа.
fwrite (a, sizeof ( double ), 1, f ); //Запись числа в двоичный файл.
}
fclose ( f ); //Закрыть файл.
return 0;
}
Задача 7.5. Вывести на экран содержимое созданного в задаче 7.4 двоичного файла abc.dat.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
FILE * f; //Описание файловой переменной.
int i, n; double *a;
f=fopen ( " abc.dat ", " rb " ); //Открыть существующий двоичный файл в режиме чтения.
fread (n, sizeof ( int ), 1, f ); //Читать из файла целое число в переменную n.
cout<<" n = "<<n<<" \n "; //Вывод n на экран.
a=new double [ n ]; //Выделение памяти для массива из n чисел.
fread ( a, sizeof ( double ), n, f ); //Чтение n вещественных чисел из файла в массив a.
for ( i =0; i<n; cout<<a [ i ]<<" \t ", i++); //Вывод массива на экран.
cout<<endl;
fclose ( f ); //Закрыть файл.
return 0;
}
Двоичный файл — последовательная структура данных, после открытия файла доступен первый байт. Можно последовательно считывать из файла или записывать их в него. Допустим, необходимо считать пятнадцатое, а затем первое число, хранящееся в файле. С помощью последовательного доступа это можно сделать следующим образом.
FILE * f; int i, n; double a; f=fopen ( " file.dat ", " rb " ); for ( i =0; i <15; fread (a, sizeof ( double ), 1, f ), i++); fclose ( f ); f=fopen ( " file.dat ", " rb " ); fread (a, sizeof ( double ), 1, f ); fclose ( f );
Как видно, такое чтение чисел из файла, а затем повторное открытие файла — не самый удачный способ. Гораздо удобнее использовать функцию перемещения указателя файла к заданному байту:
int fseek(FILE *F, long int offset, int origin);
Функция устанавливает указатель текущей позиции файла F, в соответствии со значениями начала отсчёта origin и смешения offset. Параметр offset равен количеству байтов, на которые будет смещён указатель файла относительно начала отсчёта, заданного параметром origin. Если значение offset положительно, то указатель файла смещается вперёд, если отрицательно — назад. Параметр origin должен принимать одно из следующих значений, определённых в заголовке stdio.h:
SEEK_SET— отсчёт смещения offset вести с начала файла;SEEK_CUR — отсчёт смещения offset вести с текущей позиции файла;SEEK_END — отсчёт смещения offset вести с конца файла.Функция возвращает нулевое значение при успешном выполнении операции и ненулевое, если возник сбой при выполнении смещения.
Функция fseek фактически реализует прямой доступ к любому значению в файле. Необходимо только знать месторасположение (номер байта) значения в файле. Рассмотрим использование прямого доступа в двоичных файлах на примере решения следующей задачи.
Задача 7.6. В созданном в задаче 7.4 двоичном файле $$abc.dat$$ поменять местами наибольшее и наименьшее из вещественных чисел.
Алгоритм решения задачи состоит из следующих этапов:
a.max) и минимального (min) значения и их номеров (imax, imin).min.max.Ниже приведён текст программы решения задачи с комментариями.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
FILE * f; //Описание файловой переменной.
int i, n, imax, imin;
double *a, max, min;
f=fopen ( " abc.dat ", " rb + " ); //Открыть файл в режиме чтения и записи.
fread (n, sizeof ( int ), 1, f ); //Считать из файла в переменную n количество элементов в
файле.
a=new double [ n ]; //Выделить память для хранения вещественных чисел,
//эти числа будут хранится в массиве a.
fread ( a, sizeof ( double ), n, f ); //Считать из файла в массив a вещественные числа.
//Поиск максимального, минимального элемента в массиве a, и их индексов.
for ( imax=imin =0, max=min=a [ 0 ], i =1; i<n; i++)
{
if ( a [ i ]>max)
{
max=a [ i ];
imax= i;
}
if ( a [ i ]<min )
{
min=a [ i ];
imin= i;
}
}
//Перемещение указателя к максимальному элементу.
fseek ( f, sizeof ( int )+imax* sizeof ( double ),SEEK_SET);
//Запись min вместо максимального элемента файла.
fwrite (min, sizeof ( double ), 1, f );
//Перемещение указателя к минимальному элементу.
fseek ( f, sizeof ( int )+imin * sizeof ( double ),SEEK_SET);
//Запись max вместо минимального элемента файла.
fwrite (max, sizeof ( double ), 1, f );
//Закрытие файла.
fclose ( f );
//Освобождение памяти, выделенной под массив a.
delete [ ] a;
return 0;
}
Чтение и запись данных в файл можно выполнять с помощью функций fscanf() и fprintf(). Эти функции подобны функциям scanf() и printf(), описанным в п. 2.9, за тем исключением, что работают не с клавиатурой и экраном, а с файлами. Функции имеют следующие прототипы.
Функция чтения
fscanf(указатель на файл, строка форматов, адреса переменных);
Функция записи
fprintf(указатель на файл,строка форматов, список переменных);
Далее приведён фрагмент программного кода, который демонстрирует пример записи информации в файл my.txt.
char fio [ 30 ]= "Махарадзе В."; int a=5, b=5, c =4; float s= ( float ) ( a+b+c ) / 3; FILE *f; f=fopen ( " my.txt ", " w " ); fprintf ( f, "Оценки студента % s \n ", fio ); fprintf ( f, "математика % d, физика % d, химия % d \n ", a, b, c ); fprintf ( f, "Средний балл = %.2 f \n ", s ); fprintf ( f, " \n " ); fclose ( f );
В результате будет сформирован текстовый файл:
Оценки студента Махарадзе В. математика 5, физика 5, химия 4 Средний балл = 4.67
Рассмотрим пример чтения данных из файла. Пусть в файле test.txt хранится информация:
1 Иванов Пётр 170 78.1 2 Петров Иван 180 89.6 3 Карпов Борис 167 56.7
Тогда с помощью следующих команд можно считать информацию из файла и вывести её на экран.
int i, nom;
float Ves;
int Rost;
char fio [ 15 ], name [ 15 ];
FILE * f;
f=fopen ( " test.txt ", " r " );
for ( i =0; i <3; i++)
{
//Чтение из файла
fscanf ( f, " % d % s % s % d % f \n ",nom, fio,name,Rost,Ves );
//Вывод на экран
printf ( " % d % s % s % d %.2 f \n ",nom, fio, name, Rost, Ves );
}
fclose ( f );
Для управления вводом-выводом в C++ используются:
Флаги позволяют включить или выключить один из параметров вывода на экран. Для установки флага вывода используется следующая конструкция языка C++:
cout.setf(ios::flag)
Для снятия флага применяют конструкцию
cout.unsetf(ios::flag)
здесь flag — имя конкретного флага.
Если при выводе необходимо установить несколько флагов, то можно воспользоваться арифметической операцией "или" (|). В этом случае конструкция языка C++ будет такой:
cout.setf(ios::flag1|ios::flag2|ios::flag3)
В данном случае flag1, flag2, flag3 — имена устанавливаемых флагов вывода.
В табл. 7.1 приведены некоторые флаги форматного вывода с примерами их использования.
| Флаг | Описание | cout.width(n) устанавливает ширину поля вывода, подробнее об этом в п. 7.1.2 |
Результат |
|---|---|---|---|
right |
Выравнивание по правой границе | int r=-25; cout. setf ( ios :: right ); cout.width(15); cout<<"r="<<r<<endl; |
r=-25 |
left |
Выравнивание по левой границе (по умолчанию) | double r=-25.45; cout. setf ( ios :: left ); cout.width(50); cout<<"r="<<r<<endl; |
r=-25.45 |
boolalpha |
Вывод логических величин в текстовом виде (true, false) |
bool a=true; cout<<a<<endl; cout. setf ( ios :: boolalpha); cout<<a<<endl; |
true |
dec |
Вывод величин в десятичной системе счисления (по умолчанию) | int r=-25; cout<<"r="<<r<<endl; |
r=-25 |
oct |
Вывод величин в восьмеричной системе счисления | int p=23; //Отменить, установленный по умолчанию, вывод в десятичной системе счисления cout.unsetf( ios :: dec); //Установить вывод в восьмеричной системе счисления cout. setf ( ios :: oct); cout<<"p="<<p<<endl; |
p=27 |
hex |
Вывод величин в шестнадцатеричной системе счисления | int p=23; //Отменить, установленный по умолчанию, вывод в десятичной системе счисления cout.unsetf( ios :: dec); //Установить вывод в шестнадцатеричной системе счисления cout. setf ( ios :: hex); cout<<"p="<<p<<endl; |
p=17 |
showbase |
Выводить индикатор основания системы счисления | int p=23; cout.unsetf( ios :: dec); cout. setf ( ios :: hex| ios :: showbase); cout<<"p="<<p<<endl; |
p=0x17 |
uppercase |
Использовать прописные буквы в шестнадцатеричных цифрах | int p=29; cout.unsetf( ios :: dec); cout. setf ( ios :: hex| ios :: uppercase); cout<<"p="<<p<<endl; |
p=1D |
showpos |
Выводить знак "+" для положительных чисел | int p=29; cout. setf ( ios :: showpos); cout<<"p="<<p<<endl; |
p=+29 |
scientific |
Экспоненциальная форма вывода вещественных чисел | double p=146.673; cout. setf ( ios :: scientific ); cout<<"p="<<p<<endl; |
p=1.466730e+002 |
fixed |
Фиксированная форма вывода вещественных чисел (по умолчанию) | double p=146.673; cout. setf ( ios :: fixed ); cout<<"p="<<p<<endl; |
p=146.673 |
Флаги удобно использовать в тех случаях, когда следует изменить параметры всех последующих операторов ввода-вывода. Использование большого количества флагов для управления одним или несколькими операторами ввода-вывода не совсем удобно, потом все установленные флаги придётся отключать.
Ещё одним способом форматирования является использование манипуляторов непосредственно в конструкциях cin и cout.
Манипуляторы встраиваются непосредственно в операторы ввода-вывода. C одним из манипуляторов ($$endl$$) читатель уже встречался начиная с первой главы книги. В табл. 7.2 приведены основные манипуляторы форматирования с примерами их использования. Для корректного использования всех манипуляторов необходимо подключить библиотеку:
#include <iomanip>
| Манипулятор | Манипулятор | Пример использования | Результат |
|---|---|---|---|
setw(n) |
Определяет ширину поля вывода в n символов | int r=253; cout. setf ( ios :: fixed ); cout<<"r="<<setw(8)<<r<<endl; |
r= 253 |
setprecision(n) |
Определяет количество цифр $$(n - 1)$$ в дробной части числа | double h=1234.6578; cout. setf ( ios :: fixed ); cout<<"h="<<setw(15); cout<<setprecision(3); cout<<h<<endl; |
h=1234.658 |
dec |
Перевод числа в десятичную систему (по умолчанию) | int r=0253; cout<<"r="<<dec<<r<<endl; |
; r=171 |
oct |
Перевод числа в восьмеричную систему | int r=253; cout<<"r="<<oct<<r<<endl; |
r=375 |
hex |
Перевод числа в шестнадцатеричную систему | int r=253; cout<<"r="<<hex<<r<<endl |
p=fd |
right |
Выравнивание по правой границе | int r=-25; cout.width(15); cout<<"r="<<setw(15)<<right; cout<<r<<endl; |
r=-25 |
left |
Выравнивание по левой границе (по умолчанию) | int r=-25; cout.width(15); cout<<"r="<<setw(15)<<left; cout<<r<<endl; setfill |
r=-25 |
boolalpha |
Вывод логических величин в текстовом виде (true, false) |
bool a=true; cout<<boolalpha<<a<<endl; |
true |
noboolalpha |
Вывод логических величин в числовом виде (1, 0) | bool a=true; cout<<noboolalpha<<a<<endl; |
1 |
showpos |
Выводить знак "+" для положительных чисел | int p=29; cout<<"p="<<showpos<<p<< endl; |
p=+29 |
noshowpos |
Не выводить знак "+" для положительных чисел | int p=29; cout<<"p="<< noshowpos<<p<<endl; |
p=29 |
uppercase |
Использовать прописные буквы в шестнадцатеричных цифрах | int p=253; cout<<"p="<<hex<< uppercase<<p<<endl; |
p=FD |
nouppercase |
Использовать строчные буквы в шестнадцатеричных цифрах | int p=253; cout<<"p="<<hex<<nouppercase; cout<<p<<endl; |
p=fd |
showbase |
Выводить индикатор основания системы счисления | int p=253; cout<<"p="<<hex<<uppercase <<showbase<<p<<endl; |
p=0XFD |
noshowbase |
Не выводить индикатор основания системы счисления | int p=253; cout<<"p="<<hex<<uppercase; cout<<noshowbase<<p<<endl; |
p=FD |
setfill(c) |
Установить символ с как заполнитель | cout<<"x="<<right<<
setw(10)<<setprecision(4);
cout<<setfill("!");
cout<<(float)1/7<<endl;
cout<<"x="<<left<<setw(10);
cout<<setprecision(4);
cout<<setfill("!");
cout<<(float)1/7<<endl; |
x=!!!!0.1429 x=0.1429!!!! |
scientific |
Экспоненциальная форма вывода вещественных чисел | double p=146.673; cout<<"p="<<scientific<<p<< endl; |
p=1.466730e+002 |
fixed |
Фиксированная форма вывода вещественных чисел (по умолчанию) | cout<<"p="<<fixed<<p<<endl; |
p=146.673 |
Кроме того, управлять шириной поля вывода можно с помощью операторов:
cout.width(n) — устанавливает ширину поля вывода — $$n$$ позиций;cout.precision(m) — определяет $$m$$ цифр в дробной части числа.В п. 7.1.1 и 7.1.2 были рассмотрены основные возможности форматированного ввода-вывода. При использовании конструкций cin и cout фактически происходит ввод-вывод в текстовый файл. При вводе текстовым файлом является клавиатура ПК, при выводе в качестве текстового файла выступает экран дисплея, cin и cout фактически являются именами
Существует два основных типа файлов: текстовые и двоичные. Файлы позволяют пользователю считывать большие объёмы данных непосредственно с диска, не вводя их с клавиатуры.
Текстовыми называют файлы, состоящие из любых символов. Они организуются по строкам, каждая из которых заканчивается символом "конец строки". Конец самого файла обозначается символом "конец файла". При записи информации в текстовый файл, просмотреть который можно с помощью любого текстового редактора, все данные преобразуются к символьному типу и хранятся в символьном виде.
Для работы с файлами используются специальные типы данных, называемые ifstream служит для работы с файлами в режиме чтения. Поток ofstream служит для работы с файлами в режиме записи. Для работы с файлами в режиме как чтения, так и записи служит поток iofstream.
В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream.
Для того, чтобы записать данные в текстовый файл, необходимо:
Для того, чтобы считать данные из текстового файла, необходимо:
Для того, чтобы начать работать с текстовым файлом, необходимо описать переменную типа ofstream. Например, с помощью оператора
ofstream, ifstream, iofstream, а термин "файл" для указания реального файла на диске.
будет создана переменная F для записи информации в файл. На следующем этапе файл необходимо открыть для записи. В общем случае оператор открытия потока будет иметь вид:
F.open("file", mode);
Здесь F — переменная, описанная как ofstream, file — имя файла на диске, mode — режим работы с открываемым файлом.
Файл может быть открыт в одном из следующих режимов:
ios::in — открыть файл в режиме чтения данных, этот режим является режимом по умолчанию для потоков ifstream;ios::out — открыть файл в режиме записи данных (при этом информация в существующем файле уничтожается), этот режим является режимом по умолчанию для потоков ofstream;ios::app — открыть файл в режиме записи данных в конец файла;ios::ate — передвинуться в конец уже открытого файла;ios::trunc — очистить файл, это же происходит в режиме ios::out;ios::noreplace — не открывать существующий файл.Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного ios::in — для потоков ifstream, ios::out — для потоков ofstream.
После удачного открытия файла (в любом режиме) в переменной F будет храниться true, в противном случае false. Это позволит проверять корректность операции открытия файла.
Открыть файл (в качестве примера возьмём файл abc.txt) в режиме записи можно одним из следующих способов:
//Первый способ. ofstream f; f.open ( " abc.txt ", ios::out ); //Второй способ, //режим ios::out является режимом по умолчанию для потока ofstream ofstream f; f.open ( " abc.txt " ) //Третий способ объединяет описание переменной типа поток //и открытие файла в одном операторе ofstream f( " abc.txt ", ios::out );
После открытия файла в режиме записи будет создан пустой файл, в который можно будет записывать информацию. Если нужно открыть файл, чтобы в него что-либо дописать, то в качестве режима следует использовать значение ios::app.
После открытия файла в режиме записи, в него можно писать точно также, как и на экран, только вместо стандартного устройства вывода cout необходимо указать имя открытого для записи файла.
Например, для записи в поток F переменной a оператор вывода будет иметь вид:
F<<a;
Для последовательного вывода в поток G переменных b, c и d оператор вывода станет таким:
G<<b<<c<<d;
Закрытие потока осуществляется с помощью оператора:
F.close();
В качестве примера рассмотрим следующую задачу.
Задача 7.1. Создать текстовый файл abc.txt и записать туда n вещественных чисел.
Текст программы с комментариями:
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main ( )
{
int i, n; double a;
ofstream f; //Описывает поток для записи данных в файл.
f.open ( " abc.txt " ); //Открываем файл в режиме записи,
//режим ios::out устанавливается по умолчанию.
cout<<" n = "; cin>>n; //Ввод количества вещественных чисел.
for ( i =0; i<n; i++)
{
cout<<" a = "; cin>>a; //Ввод очередного числа.
if ( i<n-1) //Если число не последнее,
f<<a<<" \t "; //записать в файл это число и символ табуляции, иначе
else f<<a; //записать только число.
}
f.close ( ); //Закрытие потока.
return 0;
}
Обратите внимание, что в текстовый файл записываются не только вещественные числа, но и символы табуляции. Таким образом, в конце файла после последнего числа находится символ табуляции. По этой причине может возникнуть проблема при чтении информации (п. 7.2.2), так как символ табуляции будет интерпретирован как вещественное число. Чтобы этого избежать в программе была применена следующая конструкция:
if (i<n-1) f<<a<<"\t"; else f<<a;
Здесь реализована проверка ввода последнего числа. После него символ табуляции отсутствует.
В результате работы программы будет создан текстовый файл abc.txt, который можно просмотреть средствами обычного текстового редактора (рис. 7.1,рис. 7.2).
(рис 7.1) Процесс работы программы к задаче 7.1. Ввод исходных данных.
(рис 7.2) Текстовый файл abc.txt, созданный программой к задаче 7.1.
Для того, чтобы прочитать информацию из текстового файла, необходимо описать переменную типа ifstream. После этого файл необходимо открыть для чтения с помощью оператора open. Если переменную назвать F, то первые два оператора будут такими:
ifstream F;
F.open("abc.txt", ios::in);
ios::in можно, конечно, опустить, ведь для потока ifstream значение ios::in является значением по умолчанию, тогда оператор open можно будет записать так F.open("abc.txt");
После открытия файла в режиме чтения, из него можно считывать информацию точно так же, как и с клавиатуры, только вместо стандартного устройства ввода cin необходимо указать имя потока, из которого будет происходить чтение данных.
Например, для чтения из потока F в переменную a оператор ввода будет иметь вид:
F>>a;
Для последовательного ввода из потока G в переменные b, с и d оператор ввода станет таким:
G>>b>>c>>d;
Два числа в текстовом файле считаются разделёнными, если между ними есть хотя бы один из символов: пробел, табуляция, символ конца строки.
Хорошо, если программисту заранее известно, сколько и каких значений хранится в текстовом файле. Однако часто просто известен тип значений, хранящихся в файле, при этом количество значений в файле может быть различным. При решении подобной проблемы необходимо считывать значения из файла по одному, а перед каждым считыванием проверять, достигнут ли конец файла. Для проверки, достигнут или нет конец файла, служит функция
f.eof();
Здесь F — имя потока, функция возвращает логическое значение: true — если достигнут конец файла, если не достигнут функция возвращает значение false.
Следовательно, цикл для чтения содержимого всего файла можно записать так.
while ( ! f.eof ( ) ) //Организован цикл, условием окончания цикла
//является достижение конца файла, в этом случае f.eof() вернёт true.
{
F>>a; //Чтение очередного значения из потока F в переменную a.
...
<обработка значения переменной a>
}
Рассмотрим следующую задачу.
Задача 7.2. В текстовом файле $$abc.txt$$ хранятся вещественные числа (рис. 7.2), вывести их на экран и вычислить их количество.
Текст программы с комментариями приведён ниже.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
ifstream f; //Поток для чтения.
float a; int n=0;
f.open ( " abc.txt " ); //Открываем файл в режиме чтения.
if ( f ) //Если открытие файла прошло корректно, то
{
while ( !f.eof ( ) ) //Организован цикл, выполнение цикла
//прервётся, когда будет достигнут конца файла.
{
f>>a; //Чтение очередного значения из потока f в переменную a.
cout<<a<<" \t "; //Вывод значения переменной a
n++; //Увеличение количества считанных чисел.
}
f.close ( ); //Закрытие потока.
cout<<" n = "<<n<<endl; //Вывод на экран количества чисел.
}
else cout<<"Файл не найден"<<endl; //Если открытие файла прошло некорректно, то
//вывод сообщения, об отсутствии такого файла.
return 0;
}
Результат работы программы к задаче 7.2:
3.14159 2.789 -21.14 543.89 -90.1 n=5
Программа работает корректно, если текстовый файл abc.txt был создан с помощью программы к задаче 7.1. Предположим, что файл создавался в текстовом редакторе, и пользователь ввёл после последней цифры символ пробела, табуляции или перехода на новую строку. Тогда результат будет таким:
3.14159 2.789 -21.14 543.89 -90.1 -90.1 n= 6
Происходит это потому, что после чтения последней цифры из потока конец файла не достигнут, оператор цикла выполняется ещё один раз, значение переменной $$n$$ увеличивается на единицу, а так как значение переменной $$a$$ не изменилось, то выводится повторно. Один из способов решения данной проблемы может быть таким:
while ( !f.eof ( ) )
{
f>>a;
if ( !f.eof ( ) ) //Проверяем, достигнут ли конец файла, если нет — печатаем значение a
{
cout<<a<<" \t ";
n++;
}
}
Если количество вещественных чисел, записанных в файл, известно заранее, то текст программы можно переписать следующим образом:
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
ifstream f;
float a; int i, n=5;
f.open ( " abc.txt " );
if ( f )
{
for ( i =1; i<=n; f>>a, cout<<a<<" \t ", i++);
f.close ( );
}
else cout<<"Файл не найден"<<endl;
return 0;
}
Существует возможность открывать файл с данными таким образом, чтобы в него можно было дописывать информацию. Рассмотрим эту возможность на примере решения следующей задачи.
Задача 7.3. В файле $$abc.txt$$ (рис. 7.2) хранится массив вещественных чисел, дописать в файл этот же массив, упорядочив его по возрастанию.
Алгоритм решения задачи очень простой. Считываем в массив данные из текстового файла, упорядочиваем массив, дописываем его в этот же файл.
Для чтения данных из файла описываем поток ifstream, открываем его в режиме чтения и последовательно, пока не достигнем конца файла, считываем все элементы в массив. Сортировку проведём методом пузырька. Обратите внимание, что поток нужно открыть так, чтобы была возможность дописать в конец файла упорядоченный массив.
Текст программы с комментариями приведён ниже.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
ifstream f; //Поток для чтения.
ofstream g; //Поток для записи.
float *a, b;
a=new float [ 100 ];
int i, j, n=0;
f.open ( " abc.txt ", ios::in ); //Открываем файл в режиме чтения.
if ( f )
{
while ( !f.eof ( ) )
{
f>>a [ n ];
n++;
}
//Сортировка массива.
for ( i =0; i<n-1; i++)
for ( j =0; j<n-i -1; j++)
if ( a [ j ]>a [ j +1 ])
{
b=a [ j ];
a [ j ]=a [ j + 1 ];
a [ j +1]=b;
}
f.close ( ); //Закрываем поток для чтения.
g.open ( " abc.txt ", ios::app ); //Открываем поток для того, чтобы дописать данные.
g<<" \n "; //Запись в файл символа конца строки
for ( i =0; i<n; i++) //Запись в файл
if ( i<n-1) g<<a [ i ]<< " \t "; //элемента массива и символа табуляции.
else g<<a [ i ]; //Запись последнего элемента массива
g.close ( ); //Закрытие файла.
}
else cout<<"Файл не найден"<<endl;
delete [ ] a;
return 0;
}
Содержимое файла abc.txt после запуска программы к задаче 7.3
3.14159 2.798 -21.14 543.89 -90.1 -90.1 -21.14 2.798 3.14159 543.89
Если в файле хранятся только числа или данные определённой структуры, то для хранения таких значений удобно пользоваться двоичными файлами. В двоичных файлах информация считывается и записывается в виде блоков определённого размера, в них могут храниться данные любого вида и структуры.
Порядок работы с двоичными и текстовыми файлами аналогичен. Для того, чтобы записать данные в двоичный файл, необходимо:
FILE *filename; Здесь filename — имя переменной, где будет храниться указатель на файл.fopen.fwrite.fclose.Для того, чтобы считывать данные из двоичного файла, необходимо:
FILE *.fopen.fread, при считывании информации следить за тем, достигнут ли конец файла.fclose.Рассмотрим основные функции, необходимые для работы с двоичными файлами.
Для открытия файла предназначена функция:
FILE *fopen(const *filename, const char *mode); где, filename — строка, в которой хранится полное имя открываемого файла, mode — строка, которая определяет режим работы с файлом; возможны следующие значения:
"rb" — открыть двоичный файл в режиме чтения;"wb" — создать двоичный файл для записи, если файл существует, то его содержимое очищается."ab" — создать или открыть двоичный файл для добавления информации в конец файла;"rb+" — открыть существующий двоичный файл в режиме чтения и записи;"wb+" — открыть двоичный файл в режиме чтения и записи, существующий файл очищается;"ab+" — двоичный файл открывается или создаётся для исправления существующей информации и добавления новой в конец файла.Функция fopen возвращает в файловой переменной NULL в случае неудачного открытия файла.
После открытия файла, в указателе содержится адрес 0-го байта файла. По мере чтения или записи значение указателя смещается на считанное (записанное) количество байт. Текущее значение указателя — номер байта, начиная с которого будет происходить операция чтения или записи.
Для закрытия файла предназначена функция
int fclose(FILE *filename);
Она возвращает 0 при успешном закрытии файла и NULL в противном случае.
Для удаления файлов существует функция
int remove(const char *filename);
Эта функция удаляет с диска файл с именем filename. Удаляемый файл должен быть закрыт. Функция возвращает ненулевое значение, если файл не удалось удалить.
Для переименования файлов предназначена функция
int rename(const char *oldfilename, const char *newfilename);
здесь первый параметр — старое имя файла, второй — новое. Возвращает 0 при удачном завершении программы.
Чтение из двоичного файла осуществляется с помощью функции
fread (void *ptr, size, n, FILE *filename)
Эта функция считывает из файла filename в массив ptr n элементов размера size. Функция возвращает количество считанных элементов. После чтения из файла указатель файла смещается на n*size байт.
Запись в двоичный файл осуществляется с помощью функции
fwrite (const void *ptr, size, n, FILE *filename);
Функция записывает в файл filename из массива ptr n элементов размера size. Функция возвращает количество записанных элементов. После записи информации в файл, указатель файла смещается на n*size байт.
Для контроля достижения конца файла есть функция
int feof(FILE * filename);
Она возвращает ненулевое значение, если достигнут конец файла.
Рассмотрим использование двоичных файлов на примере решения двух стандартных задач.
Задача 7.4.Создать двоичный файл $$abc.dat$$, куда записать целое число $$n$$ и $$n$$ вещественных чисел.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
FILE * f; //Описание файловой переменной.
int i, n; double a;
f=fopen ( " abc.dat ", " wb " ); //Создание двоичного файла в режиме записи.
cout<<" n = "; cin>>n; //Ввод числа n.
fwrite (n, sizeof ( int ), 1, f ); //Запись числа в двоичный файл.
for ( i =0; i<n; i++) //Цикл для ввода n вещественных чисел.
{
cout<<" a = "; cin>>a; //Ввод очередного вещественного числа.
fwrite (a, sizeof ( double ), 1, f ); //Запись числа в двоичный файл.
}
fclose ( f ); //Закрыть файл.
return 0;
}
Задача 7.5. Вывести на экран содержимое созданного в задаче 7.4 двоичного файла abc.dat.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
FILE * f; //Описание файловой переменной.
int i, n; double *a;
f=fopen ( " abc.dat ", " rb " ); //Открыть существующий двоичный файл в режиме чтения.
fread (n, sizeof ( int ), 1, f ); //Читать из файла целое число в переменную n.
cout<<" n = "<<n<<" \n "; //Вывод n на экран.
a=new double [ n ]; //Выделение памяти для массива из n чисел.
fread ( a, sizeof ( double ), n, f ); //Чтение n вещественных чисел из файла в массив a.
for ( i =0; i<n; cout<<a [ i ]<<" \t ", i++); //Вывод массива на экран.
cout<<endl;
fclose ( f ); //Закрыть файл.
return 0;
}
Двоичный файл — последовательная структура данных, после открытия файла доступен первый байт. Можно последовательно считывать из файла или записывать их в него. Допустим, необходимо считать пятнадцатое, а затем первое число, хранящееся в файле. С помощью последовательного доступа это можно сделать следующим образом.
FILE * f; int i, n; double a; f=fopen ( " file.dat ", " rb " ); for ( i =0; i <15; fread (a, sizeof ( double ), 1, f ), i++); fclose ( f ); f=fopen ( " file.dat ", " rb " ); fread (a, sizeof ( double ), 1, f ); fclose ( f );
Как видно, такое чтение чисел из файла, а затем повторное открытие файла — не самый удачный способ. Гораздо удобнее использовать функцию перемещения указателя файла к заданному байту:
int fseek(FILE *F, long int offset, int origin);
Функция устанавливает указатель текущей позиции файла F, в соответствии со значениями начала отсчёта origin и смешения offset. Параметр offset равен количеству байтов, на которые будет смещён указатель файла относительно начала отсчёта, заданного параметром origin. Если значение offset положительно, то указатель файла смещается вперёд, если отрицательно — назад. Параметр origin должен принимать одно из следующих значений, определённых в заголовке stdio.h:
SEEK_SET— отсчёт смещения offset вести с начала файла;SEEK_CUR — отсчёт смещения offset вести с текущей позиции файла;SEEK_END — отсчёт смещения offset вести с конца файла.Функция возвращает нулевое значение при успешном выполнении операции и ненулевое, если возник сбой при выполнении смещения.
Функция fseek фактически реализует прямой доступ к любому значению в файле. Необходимо только знать месторасположение (номер байта) значения в файле. Рассмотрим использование прямого доступа в двоичных файлах на примере решения следующей задачи.
Задача 7.6. В созданном в задаче 7.4 двоичном файле $$abc.dat$$ поменять местами наибольшее и наименьшее из вещественных чисел.
Алгоритм решения задачи состоит из следующих этапов:
a.max) и минимального (min) значения и их номеров (imax, imin).min.max.Ниже приведён текст программы решения задачи с комментариями.
#include <iostream>
#include <fstream>
using namespace std;
int main ( )
{
FILE * f; //Описание файловой переменной.
int i, n, imax, imin;
double *a, max, min;
f=fopen ( " abc.dat ", " rb + " ); //Открыть файл в режиме чтения и записи.
fread (n, sizeof ( int ), 1, f ); //Считать из файла в переменную n количество элементов в
файле.
a=new double [ n ]; //Выделить память для хранения вещественных чисел,
//эти числа будут хранится в массиве a.
fread ( a, sizeof ( double ), n, f ); //Считать из файла в массив a вещественные числа.
//Поиск максимального, минимального элемента в массиве a, и их индексов.
for ( imax=imin =0, max=min=a [ 0 ], i =1; i<n; i++)
{
if ( a [ i ]>max)
{
max=a [ i ];
imax= i;
}
if ( a [ i ]<min )
{
min=a [ i ];
imin= i;
}
}
//Перемещение указателя к максимальному элементу.
fseek ( f, sizeof ( int )+imax* sizeof ( double ),SEEK_SET);
//Запись min вместо максимального элемента файла.
fwrite (min, sizeof ( double ), 1, f );
//Перемещение указателя к минимальному элементу.
fseek ( f, sizeof ( int )+imin * sizeof ( double ),SEEK_SET);
//Запись max вместо минимального элемента файла.
fwrite (max, sizeof ( double ), 1, f );
//Закрытие файла.
fclose ( f );
//Освобождение памяти, выделенной под массив a.
delete [ ] a;
return 0;
}
Чтение и запись данных в файл можно выполнять с помощью функций fscanf() и fprintf(). Эти функции подобны функциям scanf() и printf(), описанным в п. 2.9, за тем исключением, что работают не с клавиатурой и экраном, а с файлами. Функции имеют следующие прототипы.
Функция чтения
fscanf(указатель на файл, строка форматов, адреса переменных);
Функция записи
fprintf(указатель на файл,строка форматов, список переменных);
Далее приведён фрагмент программного кода, который демонстрирует пример записи информации в файл my.txt.
char fio [ 30 ]= "Махарадзе В."; int a=5, b=5, c =4; float s= ( float ) ( a+b+c ) / 3; FILE *f; f=fopen ( " my.txt ", " w " ); fprintf ( f, "Оценки студента % s \n ", fio ); fprintf ( f, "математика % d, физика % d, химия % d \n ", a, b, c ); fprintf ( f, "Средний балл = %.2 f \n ", s ); fprintf ( f, " \n " ); fclose ( f );
В результате будет сформирован текстовый файл:
Оценки студента Махарадзе В. математика 5, физика 5, химия 4 Средний балл = 4.67
Рассмотрим пример чтения данных из файла. Пусть в файле test.txt хранится информация:
1 Иванов Пётр 170 78.1 2 Петров Иван 180 89.6 3 Карпов Борис 167 56.7
Тогда с помощью следующих команд можно считать информацию из файла и вывести её на экран.
int i, nom;
float Ves;
int Rost;
char fio [ 15 ], name [ 15 ];
FILE * f;
f=fopen ( " test.txt ", " r " );
for ( i =0; i <3; i++)
{
//Чтение из файла
fscanf ( f, " % d % s % s % d % f \n ",nom, fio,name,Rost,Ves );
//Вывод на экран
printf ( " % d % s % s % d %.2 f \n ",nom, fio, name, Rost, Ves );
}
fclose ( f );
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.