7 Работа с файлами
Во время работы на компьютере часто возникает необходимость использовать данные, которые записаны на внешних носителях информации (например, дисках) и оформлены в виде файлов данных. Файлы представляют собой последовательность байтов. Их компонентами могут быть любые данные (числа, символы, строки, массивы, структуры и др.). Использование файлов данных в программе предусматривает выполнение таких операций:
- создание потока для обмена данными между файлом и памятью;
- связывание потока с конкретным именем файла на диске и открытие файла;
- запись данных в файл или чтение их из файла;
- закрытие файла.
Для реализации этих операций существуют специальные классы, которые содержат конструкторы создания необходимых потоков:
ifstream – для создания потока чтения данных;
ofstream – для создания записи данных в файл;
fstream – используется как для записи данных так и для их чтения.
Конструкторы — это специальные функции, которые создают объекты из соответствующих классов. Конструкторы с параметрами одновременно создают соответствующий поток, связывают его с файлом на диске и открывают файл для работы. Конструкторы потоков имеют такие формы записи:
ofstream ів (“ім “,ios::out); или ofstream ів (“ім“);
ifstream ів(“ім“,ios::in); или ifstream (“ім“);
fstream ів (“ім“, ios::in | ios::out); ,
где ів — имя потока, который создается для работы с файлом;
ім – константа, или переменная типа char[], значением которой есть имя файла на диске.
Первый из конструкторов используется при записи данных в файл, второй – при чтении данных из файла, а третий – как при записи, так и при чтении данных. Примером конструктора может быть запись:
ofstream fout(“ myfile.dat”, ios::out);
Эта запись создает поток с именем “fout”, связывает его с файлом на диске, который имеет имя “myfile.dat” и открывает этот файл для записи данных. Файл “myfile.dat” будет создан в том каталоге, что и программа. Если надо создать файл в другом месте, то при записи его имени надо указать путь, например, “a:\\pvp\\myfile.dat”. Теперь этот файл будет записан на диске “а:” в папке “pvp”. Обратите внимание на то, что при записи пути нужно использовать двойные косые черточки. Если для работы с файлами использовать конструкторы без параметров в виде
ofstream ip;
Ifstream ip;
fstream ip; ,
где ip – имя соответствующего потока, то для связывания потока с именем файла на диске и открытия его для работы нужно дополнительно использовать функцию – член вида:
ip.open(“ім“ , ios:: режим | ios::режим);
Например, открытие файла для записи в него данных можно написать:
ofstream fout;
fout.open(“a:\\pvp\\myfile.dat”,ios::out);
Рассмотрим некоторые примеры работы с файлами.
Пример 7.1 Создать файл на диске и записать в него массив чисел. Затем прочитать этот файл и вывести его компоненты на экран. Программа имеет вид:
#include<iostream.h>
#include<fstream.h>
int main()
{ int i, mas[5];
ofstream fout(“massiv.dat”); //создание потока fout и открытие файла.
іf (!fout){ cout<<”Cannot open file\n”; return 1;}
for(i=0;i<5;i++)
{ cout<<” Enter “<<i<<” element\n”;
cin>>mas[i]; //ввод элементов массива с клавиатуры
fout<<mas[i]<<’ ’; } //взвод элемента в файл.
fout.close();
//чтение компонента файла в память компьютера
//и вывод на экран
ifstream fin(“massiv.dat”); //создание потока fin для чтения файла
if (!fin) { cout<<” Cannot open file fo reading\n”; return 1;}
cout<<”REZULTAT\n”;
for(i=0;i<5;i++)
{ fin>>mas[i]; //чтение очередного элемента массива с диска
cout<<”mas[“<<i<<”]=”<<mas[i]<<” “; } // взвод на экран
cout<< “\nFile reading\n”;
fin.close();
cin>>i;
return 0;}
Результат выполнения программы:
Enter 0 element
15
Enter 1 element
20
Enter 2 element
125
Enter 3 element
94
Enter 4 element
5
REZULTAT
mas[0]=15 mas[1]=20 mas[2]=125 mas[3]=94 mas[4]=5
File reading.
Пример 7.2. Запишем в файл матрицу размерностью 2х4 отдельными строками.
#include<iostream.h>
#include<fstream.h>
void main()
{ int matr[2][4], matr1[2][4];
ofstream out("filemat",ios::out); //открытие файла
for(i=0;i<2;i++)
for(j=0;j<4;j++)
{cin>> matr [i][j];
out<<matr[i][j]<<" ";}
out.close();
//читання з файлу .
ifstreram in("filemat",ios::in); //открытие файла для чтения
for(i=0;i<2;i++)
for(j=0;j<4;j++)
in>>matr1[i][j];
in.close();
// вывод матрицы на экран
cout<< “\nMatrix matr1\n”;
for(i=0;i<2;i++)
{cout<<endl;
for(j=0;j<4;j++)
cout<<matr1[i][j]<<” “;}
cin>>j;
}
Результат работы программы:
Matrix matr1
7 10 8
15 3 12 10
Пример 7.3. Записать в файл 5 фамилий, затем прочитать их и вывести на экран.
#include<iostream.h>
#include<fstream.h>
#include<conio.h>
int main()
{ char st[5][15]; int i;
// запись в файл
ofstream fout("st_file.dat");
if(!fout) {cout<<"Cannot open file\n"; return 1;}
for(i=0;i<5;i++)
{cout<<" Vvedite "<<(i+1)<<" famil\n";
cin.getline(st[i],15); //ввод очередной фамилиис клавиатуры
fout<<st[i]<<" ";} //запияь очередной фамилии в файл
fout.close();
// чиение из файла и вывод наэкран
cout<<"\nReading file\n\n";
ifstream fin("st_file.dat");
if(!fin) {cout<<"Cannot open file.dat\n"; return 1;}
for(i=0;i<5;i++)
{fin.getline(st[i],15);
cout<<st[i];}
fin.close();
getch();
return 0;
}
Результат работы программы:
Vvedite 1 famil
Avdeev N.M.
Vvedite 2 famil
Bobrov G.K.
Vvedite 3 famil
Volkov U.L.
Vvedite 4 famil
Popov T.K.
Vvedite 5 famil
Jasin H.D.
Reading file
Avdeev N.M. Bobrov G.K. Volkov U.L. Popov T.K. Jasin H.D.
В предыдущих программах запись данных в файл и их чтение из файла осуществлялось последовательно (поэлементно). Но записать или прочитать несколько данных (например, массив чисел) можно одной операцией.
Для этого используют функции – члени соответствующих классов, которые имеют вид:
ip.write((char*)&p,sizeof(p)); — при записи данных в файл,
ip.read((char*)&p,sizeof(p)); — при чтении данных из файла ,
здесь ір — имя потока ввода или вывода; р –— переменная любого типа.
Если эта переменная имеет тип char[], то операция ее приведения не нужна. Рассмотрим пример использования этих функций.
Пример 7.4 Записать в файл массив mas[] одной операцией, затем прочитать этот файл тоже одной операцией в массив mas1[] и вывести этот массив на экран.
#include<iostream.h>
#include<fstream.h>
#include<conio.h>
const int n=5;
int main()
{int i,mas1[n],mas[n]={10,20,30,40,51};
ofstream fout("file_digits.dat", ios::binary); // открытие файла для записи
if(!fout) {cout<<"Cannot open file\n"; return 1;}
fout.write((char*)&mas,sizeof(mas)); //запись массива в файл
fout.close();
ifstream fin("file_digits.dat", ios::binary); // открытие файла для чтения данных
if(!fin) {cout<<"Cannot open file for reading\n"; return 1;}
fin.read((char*)&mas1,sizeof(mas1)); // чтение из файла массива
cout<<"file reading\n";
for(i=0;i<n;i++)
cout<<mas1[i]<<' '; .
cout<<endl;
fin.close();
getch();
return 0;
}
file reading
10 20 30 40 51
Следует отметить, что запись данных в файл и их чтение чаще осуществляется отдельно в разных программах.
Рассмотрим пример, где сначала будет создан файл, в котором запишем список фамилий и их телефоны (данные типа структура). Затем в другой программе будем по запросу выводить на экран весь список или только те фамилии и телефоны, которые нам необходимы.
Пример 7.5 Программа записи структуры в файл.
#include<iostream.h>
#include<fstream.h>
#include<string.h>
struct telefon
{ char fio[15];
char tel[10];};
void main()
{ int i;
telefon spis[5];
ofstream out("struct.dat", ios::binary);
if(!out)cout<<"Cannot open file\n";
for(i=1;i<=5;i++)
{ cout<<"Enter "<<i<<"fio and telefon\n";
cin.getline(spis[i].fio,15); // ввод фамилий с клавиатуры
cin.getline(spis[i].tel,10); // ввод телефона с клавиатуры
// запись фамилии и телефона в файл.
out.write((char*)&spis[i], sizeof(spis[i] ) );
}
out.close();
}
Результат работы программы:
Enter 1 fio and telefon
Авдеев
34-67-89
Enter 2 fio and telefon
Бобров
34-56-89
Enter 3 fio and telefon
Котов
12-13-14
Enter 4 fio and telefon
Ясин
34-44-54
Enter 5 fio and telefon
Пример 7.6 Программа чтения файла, созданного предыдущей программой.
#include<iostream.h>
#include<fstream.h>
#include<string.h>
struct telefon
{ char fio[15];
char tel[10];};
main()
{ int i,p; char name[15]; bool t;
telefon spis;
ifstream in("struct2.dat", ios::binary); //открытие файла, созданного раньше
if(!in) cout<<"\nCannot open file fo reading\n";
// ввод режима работы с файлом
cout<<"Who make: reading list(1) or name(2)\n";
cin>>p; /
if(p==1) // обработка первого режима
{while (in.read(spis.fio,15)) // чтение даннях из файла “struct2.dat”
{in.read(spis.tel,10);
cout<<spis.fio<<' '<<spis.tel<<endl; }
} // вывод данных на экран
if(p==2) // обработка второго режима
{ t=true;
cout<<"Enter name\n";
cin>>name; // ввод фамилии
in.seekg(0); // к началу файла
// цикл чтения данных из файла
while (in.read(spis.fio,15))
{ in.read(spis.tel,10);
if(spis.fio==name)
{cout<<spis.fio<<' '<<spis.tel<<"\n";
t=false;}}
in.close();
if(t)cout<<"Name "<<name<<" it is not\n";}
cin>>i;
}
Результат реализации программы при первом режиме ее работы, когда нежно вывести все данные из файла:
Who make: reading list(1) or name(2)
1
Авдеев 34-67-89
Бобров 34-56-89
Котов 12-13-14
Попов 45-67-13
Ясин 34-44-54
Результат работы программы при втором режиме работы, когда нужно вывести заданную фамилию и телефон, такой:
Who make: reading list(1) or name(2)
2
Enter name
Попов
Попов 45-67-13
Функции write() и read() удобно использовать при организации прямого доступа к данным в файле. Но для этого необходимы также функции – члены, которые позволяют перемещать указатель потока в любое место файла. Эти функции имеют вид:
ip.seekp(n,dir);
ip.seekg(n,dir); .
Первая из них используется при записи данных в файл, а вторая – при их чтении.
Здесь n – параметр, который указывает количество байтов, на которое необходимо переместить указатель потока;
dir – направление перемещения указателя (необязательный параметр). Он может принимать одно из значений:
ios::beg — от начала файла;
ios::cur — от текущей позиции;
ios::end — от конца файла.
Если этот параметр не записан, перемещение указателя осуществляется с начала файла.
Рассмотрим программу, в которой используются методы прямого доступа.
Пример 7.7. Запишем в файл числовую матрицу размерностью 3х5, затем, пользуясь средствами прямого доступа, прочитаем из файла сначала вторую строку, а затем первую.
#include<iostream.h>
#include<fstream.h>
#include<iomanip.h>
const int n=3,m=5;
void main()
{ int i,j,mas[m];
char fname[]="matr.dat";
ofstream fout(fname,ios::binary);
if(!fout)cout<<"Cannot open file\n";
for(i=0;i<n;i++)
{ cout<<"Enter "<<i<<"stroku\n";
for(j=0;j<m;j++)
cin>>mas[j];
fout.write((char*)&mas,sizeof(mas)); }
fout.close();
ifstream fin(fname,ios::binary);
if(!fin)cout<<"Cannot open file for reading\n";
fin.seekg(1*sizeof(mas));
cout<<"Vivod 2 i 1 strok matrix\n\n";
fin.read((char*)&mas,sizeof(mas));
for (j=0;j<m;j++)
cout<<setw(3)<<mas[j];
cout<<endl;
fin.seekg(0);
fin.read((char*)&mas,sizeof(mas));
for(j=0;j<m;j++)
cout<<setw(3)<<mas[j];
cout<<endl;
fin.close();
cin>>i;
}
Результат работы прогаммы:
Enter 0 stroku
12 3 4 15 0
Enter 1 stroku
5 6 17 8 10
Enter 2 stroku
11 45 9 46 3
Vivod 2 i 1 strok matrix
5 6 17 8 10
3 4 15 0
7.3 Контрольные вопросы
Чем файл отличается от массива? Каное основное назначение файлов?
Дайте определение файлу и потоку.
Какие операции необходимо выполнить при работе с файлом данных?
Назовите способы создания потоков и открытия файлов.
Какие данные можно записывать в файл?
Какие функции используют при организации прямого доступа к данным в файле?
Какой порядок создания файла?
СПИСОК ЛИТЕРАТУРЫ:
Основи програмування мовою С++: Навчальний посібник/ Є.П. Путятін, В.П. Степанов, В.П. Пчелінов, Т.Г. Долженкова, О.О. Матат. – Харків: ТОВ „Компанія СМІТ”, 2005. — 320 с.
Керниган Б., Ритчи Д. Язык программирования Си: Пер. с англ. —М.: Финансы и статистика, 1992. — 272 с.
Страуструп Б. Язык программирования С++. Часть 1. — Киев: "ДиаСофт", 1993. — 264 с.
Страуструп Б. Язык программирования С++. Часть 2. — Киев: "ДиаСофт", 1993. — 296 с.
Подбельский В.В. Язык Си+: Учеб. пособие. — М.: БИНОМ, 1995. — 400 с.
Глушаков С.В. и др. Язык программирования С++. —Харьков: Фолио, 2002. — 500 с.
Х.М.Дейтел, П.Дж. Дейтел Как программировать на С++.- М.:ЗАО «Издательство БИНОМ», 2000 г. — 1024 с.
Ван Тассел Д. Стиль, разработка, отладка и испытание программ.-M.:Мир,1985.
Проценко В.С. Техніка програмування мовою С.-Навч. Посібник. –К.:Либідь, 1993. — 224с.
Жешке Р. Толковый словарь стандарта языка Си: — С.-Петербург: Питер, 1994. — 221с.
Язык Си. Книга ответов: Пер. с англ. — М.: Финансы и статистика, 1994. — 160 с.
Бондарев В.М. Программирование на С++.- Харьков: «Компания СМИТ», 2004. — 284с
