Практическая работа №5 "Программирование с использованием двоичных файлов"
методическая разработка по теме
Представлен теоретический материал, пример программы на C++ Builder, индивидуальное задание для выполнения практической работы.
Скачать:
Вложение | Размер |
---|---|
Практическая работа "Программирование с использованием двоичных файлов" | 201 КБ |
Предварительный просмотр:
Практическая работа №5 Программирование с использованием двоичных файлов
1. Цель работы:
Изучить правила работы двоичными файлами в C++ Builder.
Написать программу работы с двоичными файлами.
2. Темы для предварительной проработки
1). Среда разработки C++ Builder
2). Компоненты C++ Builder
3) Двоичные файлы в С++.
3. Теоретический материал
Работа с двоичными файлами в стиле С
Двоичный файл представляет собой последовательность символов без разделителей. Порядок следования символов такой же, как они хранятся в оперативной памяти. Двоичные файлы имеют меньший объем, читаются и записываются быстрее. Единственный недостаток - трудность отладки. Ввод и вывод данных чаще всего производится функциями 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)
{Memol->Lines->Add("Файл не удалось открыть ");return;}
for (i=0; i<=80; i++) {
fread (s1+i, sizeof(char),1,lw); if (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); Memol ->Lines->Add(s2);
Memol->Lines->Add(lntToStr(num));
Memol ->Lines->Add(s3); fclose(lw);
В приведенном примере чтение проводилось последовательно. Узнать текущую позицию указателя можно с помощью функции ftell. Для произвольного чтения данных можно перемещать указатель в произвольную позицию с помощью функции fseek.
fseek(F, set, nn)
где F- указатель на файл; set - число байт, на которое производится сдвиг от точки отсчета; nn - точка отсчета (0 - начало файла; 1 - текущая позиция; 2 -конец файла).
Наиболее полезна эта функция в файлах, состоящих из записей одного размера.
Работа с двоичными файлами в стиле С++
В C++ файл открывается путем связывания его с потоком. Поток, который предполагается использовать для операций как ввода, так и вывода, должен быть объявлен как объект класса fstream. Например, при выполнении следующего фрагмента кода будет создан входной поток, выходной и поток, позволяющий выполнение операций в обоих направлениях.
ifstream in; // входной поток
ofstream out; // выходной поток
fstream both; // поток ввода-вывода
Чтобы открыть файл, используйте функцию open ().
Создав поток, его нужно связать с файлом. Это можно сделать с помощью функции open (), причем в каждом из трех потоковых классов есть своя функция-член open (). Представим их прототипы.
void ifstream::open(const char * filename,ios::openmode mode = ios::in);
void ofstream::open(const char * filename,ios::openmode mode = ios::out I ios::trunc);
void fstream::open(const char * filename,ios::openmode mode = ios::in | ios::out);
Здесь элемент filename означает имя файла, которое может включать спецификатор пути. Элемент mode определяет способ открытия файла. Он должен принимать одно или несколько значений перечисления openmode, которое определено в классе ios.
ios | app |
ios | ate |
ios | binary |
ios | in |
ios | out |
ios | trunc |
Несколько значений перечисления openmode можно объединять посредством логического сложения (ИЛИ).
На заметку. Параметр mode для функции fstream:: open () может не устанавливаться по умолчанию равным значению in | out (это зависит от используемого компилятора). Поэтому при необходимости этот параметр вам придется задавать в явном виде.
Включение значения ios :: app в параметр mode обеспечит присоединение к концу файла всех выводимых данных. Это значение можно применять только к файлам, открытым для вывода данных. При открытии файла с использованием значения ios::ate поиск будет начинаться с конца файла. Несмотря на это, операции ввода-вывода могут по-прежнему выполняться по всему файлу.
Значение ios :: in говорит о том, что данный файл открывается для ввода данных, а значение ios :: out обеспечивает открытие файла для вывода данных.
Значение ios :: binary позволяет открыть файл в двоичном режиме. По умолчанию все файлы открываются в текстовом режиме. Как упоминалось выше, в текстовом режиме могут происходить некоторые преобразования символов (например, последовательность, состоящая из символов возврата каретки и перехода на новую строку, может быть преобразована в символ новой строки). При открытии файла в двоичном режиме никакого преобразования символов не выполняется. Следует иметь в виду, любой файл, содержащий форматированный текст или еще необработанные данные, можно открыть как в двоичном, так и в текстовом режиме. Единственное различие между этими режимами состоит в преобразовании (или нет) символов.
Использование значения ios::trunc приводит к разрушению содержимого файла, имя которого совпадает с параметром filename, а сам этот файл усекается до нулевой длины. При создании выходного потока типа ofstream любой существующий файл с именем filename автоматически усекается до нулевой длины.
При выполнении следующего фрагмента кода открывается обычный выходной файл.
ofstream out; out.open("тест");
Поскольку параметр mode функции open () по умолчанию устанавливается равным значению, соответствующему типу открываемого потока, в предыдущем примере вообще нет необходимости задавать его значение.
Не открытый в результате неудачного выполнения функции open () поток при использовании в булевом выражении устанавливается равным значению ЛОЖЬ. Этот факт может служить для подтверждения успешного открытия файла, например, с помощью такой if-инструкции.
if(!mystream) {
cout << "He удается открыть файл.\n"; // обработка ошибки
Прежде чем делать попытку получения доступа к файлу, следует всегда проверять результат вызова функции open ().
Можно также проверить факт успешного открытия файла с помощью функции is_open (), которая является членом классов fstream, if stream и o stream. Вот ее прототип.
bool is_open();
Эта функция возвращает значение ИСТИНА, если поток связан с открытым файлом, и ЛОЖЬ — в противном случае. Например, используя следующий код, можно узнать, открыт ли в данный момент потоковый объект mystream.
if(!mystream.is_open()) {
cout << "Файл не открыт.\n";
Хотя вполне корректно использовать функцию open () для открытия файла, в большинстве случаев это делается по-другому, поскольку классы ifstream, ofstream и fstream включают конструкторы, которые автоматически открывают заданный файл. Параметры у этих конструкторов и их значения (действующие по умолчанию) совпадают с параметрами и соответствующими значениями функции open (). Поэтому чаще всего файл открывается так, как показано в следующем примере.
ifstream mystream("myfile"); // файл открывается для ввода
Если по какой-то причине файл открыть невозможно, потоковая переменная, связываемая с этим файлом, устанавливается равной значению ЛОЖЬ.
Чтобы закрыть файл, вызовите функцию close ().
Чтобы закрыть файл, используйте функцию-член close (). Например, чтобы закрыл файл, связанный с потоковым объектом mystream, используйте такую инструкцию.
mystream.close() ;
Функция close () не имеет параметров и не возвращает никакого значения.
Неформатированный ввод-вывод данных в двоичном режиме
Форматированные текстовые файлы полезны во многих ситуациях, но они не обладают гибкостью неформатированных двоичных файлов. Поэтому C++ поддерживает ряд функций файлового ввода-вывода в двоичном режиме, которые могут выполнять операции без форматирования данных.
Для выполнения двоичных операций файлового ввода-вывода необходимо открыть файл с использованием спецификатора режима ios::binary. Необходимо отметить, что функции обработки неформатированных файлов могут работать с файлами, открытыми в текстовом режиме доступа, но при этом могут иметь место преобразования символов, которые сводят на нет основную цель выполнения двоичных файловых операций.
Функция get () считывает символ из файла, а функция put () записывает символ в файл.
В общем случае существует два способа записи неформатированных двоичных данных в файл и считывания их из файла. Первый состоит в использовании функции-члена put () (для записи байта в файл) и функции-члена get () (для считывания байта из файла). Второй способ предполагает применение "блочных" С++-функций ввода-вывода read () и write ().
Использование функций get () и put ()
Функции get () и put () имеют множество форматов, но чаще всего используются следующие их версии:
istream &get (char &ch);
ostream &put(char ch);
Функция get() считывает один символ из соответствующего потока и помещает его значение в переменную ch. Она возвращает ссылку на поток, связанный с предварительно открытым файлом. При достижении конца этого файла значение ссылки станет равным нулю. Функция put() записывает символ ch в поток и возвращает ссылку на этот поток.
При выполнении следующей программы на экран будет выведено содержимое любого заданного файла. Здесь используется функция get().
// Отображение содержимого файла с помощью функции get().
#include
char ch;
while(in) { // При достижении конца файла потоковый
// объект in примет значение false,
in.get(ch);
if (in) cout << ch;
in.close () ;
При достижении конца файла потоковый объект in примет значение ЛОЖЬ, которое остановит выполнение цикла while.
Существует более короткий вариант цикла, предназначенного для считывания и отображения содержимого файла.
while(in.get(ch)) cout << ch;
Этот вариант также имеет право на существование, поскольку функция get() возвращает потоковый объект in, который при достижении конца файла примет значение false.
В следующей программе для записи строки в файл используется функция put().
// Использование функции put() для записи строки в файл.
#include
char *p = "Всем привет!";
ofstream out(test", ios::out | ios::binary);
while(*p) out.put(*p++);
out.close ();
Считывание и запись в файл блоков данных
Чтобы считывать и записывать в файл блоки двоичных данных, используйте функции-члены read() и write (). Их прототипы имеют следующий вид.
istream &read(char *buf, streamsize пит);
ostream &write(const char *buf, int streamsize пит);
Функция read () считывает пит байт данных из связанного с файлом потока и помещает их в буфер, адресуемый параметром buf. Функция write () записывает num байт данных в связанный с файлом поток из буфера, адресуемого параметром buf. Как упоминалось выше, тип streamsize определен как некоторая разновидность целочисленного типа. Он позволяет хранить самое большое количество байтов, которое может быть передано в процессе любой операции ввода-вывода.
Функция read () вводит блок данных, а функция write () выводит его.
При выполнении следующей программы сначала в файл записывается массив целых чисел, а затем он же считывается из файла.
// Использование функций read() и write().
#include
int n[5] = {1, 2, 3, 4, 5};
register int i;
ofstream out("test", ios::out | ios::binary);
out.write ( (char *) &n, sizeof n); out.close();
for(i=0; i<5; i++) // очищаем массив
n[i] = 0;
ifstream in ("test", ios : :in | ios::binary);
if(!in) {cout << "He удается открыть файл.\n";return 1; }
in.read((char *) &n, sizeof n);
for(i=0; i<5; i++) // Отображаем значения, считанные из файла,
cout << n[i] << " ";
in.close ();
Обратите внимание на то, что в инструкциях обращения к функциям read () и write () выполняются операции приведения типа, которые обязательны при использовании буфера, определенного не в виде символьного массива.
Функция gcount () возвращает количество символов, считанных при выполнении последней операции ввода данных.
Если конец файла будет достигнут до того, как будет считано пит символов, функция read () просто прекратит выполнение, а буфер будет содержать столько символов, сколько удалось считать до этого момента. Точное количество считанных символов можно узнать с помощью еще одной функции-члена gcount (), которая имеет такой прототип.
streamsize gcount();
Функция gcount () возвращает количество символов, считанных в процессе выполнения последней операции ввода данных.
4. Пример
Записать в двоичный файл в стиле С++ данные ведомости сдачи экзаменационной сессии.
Unit1.cpp
#define n 5
struct stud {
char fam[15];
int kurs;
int grup;
float ball;};
stud st[n],sz[n];
int kol=0;
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender){
if(kol
//st[kol].fam=Edit1->Text;
strcpy(st[kol].fam,Edit1->Text.c_str());
st[kol].kurs=StrToInt(Edit2->Text);
st[kol].grup=StrToInt(Edit2->Text);
st[kol].ball=StrToFloat(Edit4->Text);
//st[kol].ball=FloatToStr(Edit4->Text,ffGeneral,4,2);
Edit1->Text=""; Edit2->Text="";
Edit3->Text=""; Edit4->Text="";
Label5->Caption="Число записей "+IntToStr(kol+1);
kol++;
}
else Button1->Enabled=false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{int i=0; Memo1->Clear();
ifstream in("z.dat");
if(!in) {ShowMessage("He удается открыть файл."); }
while(! in.eof()) {in.read((char *) &sz[i], sizeof(stud));
if (in){
//ShowMessage("111");
Memo1->Lines->Add(IntToStr(i));
Memo1->Lines->Add(sz[i].fam);
Memo1->Lines->Add(IntToStr(sz[i].kurs));
Memo1->Lines->Add(IntToStr(sz[i].grup));
Memo1->Lines->Add(FloatToStrF(sz[i].ball,ffGeneral,5,3));
i++; }
}
in.close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{int i; AnsiString aaa; Memo2->Clear();
ofstream out("z.dat",ios::app);
for (i=0; i
out.write((char *) &st[i], sizeof(stud)); }
for (i=0; i<5; i++){
Memo2->Lines->Add(st[i].fam);
Memo2->Lines->Add(IntToStr(st[i].kurs));
Memo2->Lines->Add(IntToStr(st[i].grup));
Memo2->Lines->Add(FloatToStrF(st[i].ball,ffGeneral,5,3));
}
out.close();
}
//---------------------------------------------------------------------------
5. Задание
Преобразовать программу, чтобы вывод в мемо-поле при чтении файла осуществлялся по заданному признаку – значение среднего балла, номер группы, курс.
6. Индивидуальное задание
См. задание к практической работе №4.
Санкт-Петербургский колледж информационных технологий
Методические указания
к выполнению практической работы №5
«Программирование с использованием двоичных файлов»
Разработала
Мастер
производственного обучения
Шапкина Л.М.
По теме: методические разработки, презентации и конспекты
Практическая работа №2 "Программирование с использованием строк"
Представлен теоретический материал, пример программы в среде C++ Buider, индивидуальные задания для выполнения практической работы....
Практическая работа №3 "Программирование с использованием структур"
Представлен теоретический материал, пример программы на C++ Builder, индивидуальное задание для выполнения практической работы....
Практическая работа №4 "Программирование с использованием текстовых файлов"
Представлен теоретический материал, пример программы на C++ Builder, индивидуальное задание для выполнения практической работы....
Практическая работа «Расчет показателей использования основных средств и оборотных средств»
Практическая работа по экономике организации для студентов СПО....
САПР КОМПАС. Практическая работа. Использование вспомогательных параллельных прямых при создании чертежа.
САПР КОМПАС. Практическая работа. Использование вспомогательных параллельных прямых при создании чертежа. В практической работе три задания.Применение вспомогательных параллельных прямых студенты изуч...
Практическая работа "Представление информации в двоичной системе счисления"
в практической работе представлены три заания: 1. Перевод из десятичной системы счисления в двоичную; 2. Перевод из двоичной системы счисления в десятичную; 3. Арифметические действия в двоичной систе...
Практическая работа №7. Комплексное использование возможностей текстовых редакторов.
Содержит итоговые практические задания по разделу "Текстовые процессоры"...