Лабораторная работа №2

Программирование с использованием файлов

Цель лабораторной работы: изучить правила работы с компонентами TOpenDialog и TSaveDialog. Написать программу с использованием файлов и данных типа “структура”.

7.1.Работа с файлами

В языках C и С++ файл рассматривается как поток (stream), представляющий собой последовательность считываемых или записываемых байтов. При этом последовательность записи определяется самой программой.

С++ Builder позволяет работать с файлами тремя различными способами:

1)      работа в стиле С;

2)       работа в стиле С++;

1)       использование библиотечных компонентов.

7.1.1.Работа с файлами в стиле С

Каждый файл в программе на С++ должен быть связан с некоторым указателем. Этот указатель имеет тип FILE (определен в stdio.h) и используется во всех операциях с файлами.

Синтаксис операции следующий:

# include < stdio.h >

FILE *fin, *fout;

Подпись: r	Открывает файл для чтения
r+	Открывает существующий файл для чтения и записи
w	Создает файл для записи. Если файл уже существует, его содержимое уничтожается
w+	Создает файл для чтения и записи. Если файл уже существует, его содержимое уничтожается
a	Открывает файл для записи данных в конец файла. Если файл отсутствовал, он создается
a+	Открывает файл для чтения или записи данных в конец файла. Если файл отсутствовал, он создается
После режима может добавляться символ “t” - текстовый файл или “b” - бинарный файл. Если символ не указан, то по умолчанию считается что файл текстовый. Например:

Для работы с файлом его необходимо открыть функцией fopen, первый параметр которой содержит имя файла и путь к нему, а второй - режим открытия файла. Функция возвращает указатель на файл. Часто

fin=fopen(“a:\\dat.txt”,”r”);

fout=fopen(“a:\\out.txt”,”w”);

При записи обмен происходит не непосредственно с файлом, а с некоторым буфером. Информация из буфера переписывается в файл только при его переполнении или при закрытии файла.

После окончания работы с файлом он обязательно должен быть закрыт функцией fclose (FILE *).

Если файл не удалось открыть, то возвращается нулевой указатель (NULL). Например:

# include < stdio.h >

FILE *lw;

if ((lw=fopen("a.text","r")) == NULL)

{

Memo1->Lines->Add("Файл не открыт"); return;

}

fclose(lw);

7.1.1.1.      Работа с текстовыми файлами

Для записи в текстовый файл наиболее часто используется функция fprintf: int *fprintf(FILE *stream, const char *format[]);

где параметр format определяет строку форматирования аргументов, заданных своими адресами. Обычно эта строка состоит из последовательности символов “%”, после которых следует символ типа данных:

 

I  или i

Десятичное, восьмеричное или шестнадцатеричное целое

D или d

Десятичное целое

U или u

Десятичное целое без знака

E или e

Действительное с плавающей точкой

s

Строка символов

c

Символ

 

Из отрытого текстового файла можно читать информацию как по строкам, так и посимвольно. Чтение строки осуществляется функцией fgets : char *fgets(char *st, int n, FILE *stream);

где st - указатель на буфер, в который считается строка; n - число читаемых символов; stream - указатель на файл. Строка читается до тех пор, пока не будет прочитано n-1 символов, или до конца строки \n. В конце прочитанной строки ставится нулевой символ.

Для проверки достижения конца файла используется функция feof(F).

Чтение форматированных данных можно осуществлять с помощью функции fscanf:

int *fscanf(FILE *stream, const char *format[]);

Строка форматирования строится аналогично fprintf.

Следует обратить внимание на то, что при чтении данных всегда указываются адреса переменных (&), а не сами переменные.

Пример записи и чтения данных из файла:

# include < stdio.h >

…..

Memo1->Clear();

FILE *lw;

// Запись данных в файл i

f ((lw=fopen("a.text","wt")) == NULL)

{

Memo1->Lines->Add("Файл не удалось создать");

return;

}

int num=10;

char st[12] = "ИНФОРМАЦИЯ",sr [30];

fprintf(lw,"%s \n В группе %i человек"^, num);  fclose(lw);

// Чтение данных из файла

if ((lw=fopen("a.text","rt")) == NULL)

{

Memo1->Lines->Add("Файл не удалось открыть "); return;

}

  while (!feof(lw)) { fgets(sr,30,lw);

if (sr[strlen(sr)-1] =='\n') sr[strlen(sr)-1]=0;

Memo1->Lines->Add(sr) ;

}

fclose(lw);

7.1.1.2.      Работа с двоичными файлами

Двоичный файл представляет собой последовательность символов без разделителей. Порядок следования символов такой же, как они хранятся в оперативной памяти. Двоичные файлы имеют меньший объем, читаются и записываются быстрее. Единственный недостаток - трудность отладки. Ввод и вывод данных чаще всего производится функциями fwrite и fread:

fwrite (dd,size,n,f);

fread (dd,size,n,f);

где dd - указатель на вводимые данные; size - размер передаваемых данных в байтах; n - число передаваемых данных; f - указатель на файл.

Пример работы с двоичным файлом:

# include < stdio.h >

Memo1->Clear();

FILE *lw;

// Ввод данных в файл

if ((lw=fopen("a.text","wb")) == NULL)

{

Memo1->Lines->Add("Файл не удалось создать "); return;

}

int i,num=10;

char s1[80] = "ИНФОРМАЦИЯ", s2[80], s3[80] ;

fwrite (s1,sizeof(char),strlen(s1)+1,lw);

 fwrite ("в группе",sizeof(char),9,lw);

fwrite (&num,sizeof(int),1,lw);

 fwrite ("человек",sizeof(char),8,lw); fclose(lw);

// Чтение данных из файла

if ((lw=fopen("a.text","rb")) == NULL)

{

Memo1->Lines->Add("Файл не удалось открыть ");

return;

}

for (i=0; i<=80; i++) {

fread (s1+i, sizeof(char),1,lw);

f (s1[i]=='\0') break;

}

for (i=0; i<=80; i++) {

fread (s2+i, sizeof(char),1,lw);

if (s2[i]=='\0') break;

}

fread (&num,sizeof(int),1,lw);

for (i=0; i<=80; i++) {

fread (s3+i, sizeof(char),1,lw);

if (s3[i]=='\0') break;

}

Memo1->Lines->Add(s1);

Memo1->Lines->Add(s2);

Memo1->Lines->Add(IntToStr(num));

 Memo1->Lines->Add(s3); fclose(lw);

В приведенном примере чтение проводилось последовательно. Узнать текущую позицию указателя можно с помощью функции ftell. Для произвольного чтения данных можно перемещать указатель в произвольную позицию с помощью функции fseek.

fseek(F, set, nn)

где F- указатель на файл; set - число байт, на которое производится сдвиг от точки отсчета; nn - точка отсчета (0 - начало файла; 1 - текущая позиция; 2 - конец файла).

Наиболее полезна эта функция в файлах, состоящих из записей одного размера.

7.1.2.        Работа с использованием дескрипторов

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

7.1.3.Работа с файлами в стиле C++

В C++ определены три класса файлового ввода/вывода: ifstream - входные данные для чтения; ofstream - выходные файлы для записи; fstream - файлы для чтения и записи.

Очень удобно применять следующие операции: поместить в поток (<<) и извлечь из потока (>>).

Пример программы:

#include <fstream.h>

Memo1->Clear();

// Ввод данных в файл

ofstream lw ("a.text");

if (!lw)

{

Memo1->Lines->Add("Файл не удалось создать ");

return;

}

int num=10; double k=5.67;

char s[20] = "ИНФОРМАЦИЯ";

lw << num << ' ' <<k << ' ' << s << endl;

w.close();

// Чтение данных из файла

ifstream lx ("a.text"); if (!lx)

{

Memo1->Lines->Add("Файл не удалось открыть ");

return;

}

lx >> num >> k >> s;

Memo1->Lines->Add(IntToStr(num));

Memo1->Lines->Add(FloatToStr(k));

Memo1->Lines->Add(s);

lx.close();

Помимо этих операций поместить в поток можно еще с помощью функций put и write. Возможности ввода/вывода можно существенно расширить, используя манипуляторы потока.

7.1.3.        Работа с файлами с помощью компонентов

Работа с файлами осуществляется в помощью методов LoadFromFile и SaveToFile. Через компоненты можно работать не только с текстовыми файлами, но и с файлами мультимедиа и изображениями.

7.2.               Компоненты TOpenDialog и TSaveDialog

Компоненты TOpenDialog и TSaveDialog находятся на странице DIALOGS. Все компоненты этой страницы являются невизуальными, т.е. не видны в момент работы программы. Поэтому их можно разместить в любом удобном месте формы. Оба рассматриваемых компонента имеют идентичные свойства и различаются только внешним видом. После вызова компонента появляется диалоговое окно, с помощью которого выбирается имя программы и путь к ней. В случае успешного завершения диалога имя выбранного файла и маршрут поиска содержатся в свойстве FileName. Для фильтрации файлов, отображаемых в окне просмотра, используется свойство Filter, а для задания расширения файла, в случае, если оно не задано пользователем, - свойство DefaultExt. Если необходимо изменить заголовок диалогового окна, используется свойство Title.

7.3.               Порядок выполнения задания

Задание: написать программу, вводящую в файл или читающую из файла ведомость абитуриентов, сдавших вступительные экзамены. Каждая запись должна содержать фамилию, а также оценки по физике, математике и сочинению. Вывести список абитуриентов, отсортированный в порядке уменьшения их среднего балла, и записать эту информацию в текстовой файл.

7.3.1.        Настройка компонентов TOpenDialog и TSaveDialog

Для установки компонентов TOpenDialog и TSaveDialog на форму необходимо на странице Dialogs меню компонентов щелкнуть мышью по пиктограмме или и поставить её в любое свободное место формы. Установка фильтра производится следующим образом. Выбрав соответствующий компонент, дважды щелкнуть по правой части свойства Filter инспектора объектов. Появится окно Filter Editor, в левой части которого записывается текст, характеризующий соответствующий фильтр, а в правой части - маска. Для OpenDialogl установим значения маски, как показано на рис. 7.1. Формат *.dat

 

Рис.7.1.

означает, что будут видны все файлы с расширением dat, а формат *.* - что будут видны все файлы (с любым именем и с любым расширением).

Для того чтобы файл автоматически записывался с расширением .dat, в свойстве DefaultExt запишем требуемое расширение - .dat.

Аналогичным образом настроим SaveDialog1 для текстового файла (расширение .txt).

7.3.2.Работа с программой

После запуска программы на выполнение появится диалоговое окно программы. Кнопка “Ввести запись” видна не будет. Необходимо создать новый файл записей, нажав на кнопку “Создать”, или открыть ранее созданный, нажав на кнопку “Открыть”. После этого станет видна кнопка “Ввести запись” и можно будет вводить записи. При нажатии на кнопку “Сортировка” будет проведена сортировка ведомости по убыванию среднего балла и диалоговое окно примет вид, как на рис. 7.2. Затем при нажатии на кнопку “Сохранить” будет создан текстовой файл, содержащий отсортированную ведомость. Файл записей закрывается одновременно с программой при нажатии на кнопку Closeили p3.

Рис 7.2.

         Текст программы:

//-----------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Lab7F.h"

#include <stdio.h>;

//-------------------------------------------------------

#pragma  package(smart_init)

#pragma resource "*dfm"

TForm1 *Form1;

typedef  struct {

char  FIO[30];

Byte  otc[3];

Single  sball;

} TStudent;

TStudent Stud[100];

 int nzap=0;

FILE *Fs;

//-------------------------------------------------------

___fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//-------------------------------------------------------

void  fastcall TForm1::FormCreate(TObject *Sender)

{

Edit1->Clear();

Edit2->Clear();

Edit3->Clear();

Edit4->Clear();

RichEdit1->Clear();

Button1->Hide();

}

//---------------------------------------------------------------------

void___fastcall TForm1::Button2Click(TObject *Sender)

{

OpenDialog1->Title="New File"; if (OpenDialog1->Execute())

{

char *FileNameS= OpenDialog1->FileName.c_str();

if ((Fs=fopen(FileNameS,"wb"))==NULL) {

ShowMessage("File no created"); return;     }

Button1->Show();

}

}

//---------------------------------------------------------------------

void  fastcall TForm1::Button1Click(TObject *Sender)

{

strcpy(Stud[nzap].FIO,Edit1->Text.c_str());

Stud[nzap].otc[0]=StrToInt(Edit2->Text);

Stud[nzap].otc[1]=StrToInt(Edit3->Text);

Stud[nzap].otc[2]=StrToInt(Edit4->Text);

Stud[nzap].sball=(Stud[nzap].otc[0]+Stud[nzap].otc[1]+Stud[nzap].otc[2])/3.0;

RichEdit1->Lines->Add(AnsiString(Stud[nzap].FIO)+" "   +IntToStr(Stud[nzap].otc[0])+" "

         +IntToStr(Stud[nzap].otc[1])+" "

+IntToStr(Stud[nzap].otc[2])+" ");

fwrite(&Stud[nzap],sizeof(TStudent),1,Fs);

nzap++;

}

//-------------------------------------------------------

void___ fastcall TForm1::Button3Click(TObject *Sender)

{

OpenDialog1->Title="Open File";

 if (OpenDialog1->Execute())

{

char *FileNameS= OpenDialog1->FileName.c_str();

if ((Fs=fopen(FileNameS,"rb"))==NULL) {

ShowMessage("File is not opened");

return;                                  }

Button1->Show();

RichEdit1->Clear();

nzap=0;

do

{

fread(&Stud[nzap],sizeof(TStudent),1,Fs);

if (feof(Fs)) break;

RichEdit1->Lines->Add(AnsiString(Stud[nzap].FIO)+" "

 +IntToStr(Stud[nzap].otc[0])+" "

 +IntToStr(Stud[nzap].otc[1])+" "

+IntToStr(Stud[nzap].otc[2])+" ");

nzap++;

}

while(True);

Button1->Show();

}

}

//----------------------------------------------------------------------------

void___ fastcall TForm1::Button4Click(TObject *Sender)

{

TStudent tmp;

 for(int i=0;i<nzap-1;i++)

for(int j=i;j<nzap;j++)

if (Stud[i].sball<Stud[j].sball)

{

tmp=Stud[i];

Stud[i]=Stud[j];

Stud[j]=tmp;

}

RichEdit1->Clear();

RichEdit1->Lines->Add(" Результат:");

for(int i=0;i<nzap;i++)

RichEdit1->Lines->Add(AnsiString(Stud[i].FIO)+" "

+IntToStr(Stud[i].otc[0])+" "

+IntToStr(Stud[i].otc[1])+" "

+IntToStr(Stud[i].otc[2])+" ");

}

//---------------------------------------------------------------------

void___fastcall TForm1::Button5Click(TObject *Sender)

{

SaveDialog1->Title="Save File"; if (SaveDialog1->Execute())

{

AnsiString FileNameR = SaveDialog1->FileName;

RichEdit1->Lines->SaveToFile(FileNameR);

}

}

//---------------------------------------------------------------------

void___fastcall TForm1::BitBtn1Click(TObject *Sender)

{

fclose(Fs);

}

7.4.Выполнение индивидуального задания

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