Лабораторная работа №4
Вариант 6.
Задание 1. Используя функции и режим меню, создать файл из 10 структур, просмотреть файл, добавить в файл новую информацию и, применяя режим прямого доступа, выполнить задание по своему варианту. Структура имеет вид: фамилия, номер телефона, дата рождения. Внести в начало списка информацию о четырех новых знакомых.
Программа с пояснениями:
// Lab5.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
struct Kontakt{ //Искомая структура (Имя, телефон, дата рождения)
char FIO[10];
char Tel[17];
char Date[10];};
struct Kontakt t;
void input(); //Процедура ввода новой таблицы
void print(); //Процедура вывода таблицы на экран
void app(); //Процедура добавления записи в начало таблицы с помощью Temp файла
void add(); //Процедура добавления записи в начало таблицы произвольным доступом
FILE *f;
int main(int argc, char* argv[])
{
char c;
while (1){
system("cls"); //В Visual C нет clrscr
puts("1. New"); //Выводим менюшку на экран
puts("2. View");
puts("3. Add");
puts("4. Add ver 2.");
puts("0. Exit");
c=getch();
switch(c){ //Что будем делать:
case '1':input();break; //Вводим таблицу заново
case '2':print();break; //Печатаем
case '3':app();break; //Добавляем запись
case '4':add();break; //Добавляем запись
case '0':return 0;
default : puts(" Wrong key");
}
}
return 0;
}
void input()
//Ввод данных в пустой файл. Ничего сложного, тем более, что эта же самая программа
//приведена в лекциях.
{
char ch;
f=fopen("Data.dat","wb"); //Режим записи, пишем с начала файла и дальше
do{
system("cls");
printf("\n Input new kontakt\n"); //Получаем структуру с клавиатуры
printf("\n FIO: "); scanf("%s",t.FIO);
printf(" Tel: "); scanf("%s",t.Tel);
printf(" Birthdate: "); scanf("%s",t.Date);
fwrite(&t,sizeof(t),1,f); //Пишем в файл
printf("\n Exit? y/n ");
ch=getch();
}
while (ch != 'y');
fclose(f);
}
void print()
//Вывод данных из файла на экран. Функция идентична фнкции, предложенной в лекциях
{
int i;
system("cls");
f=fopen("Data.dat","rb"); //Режим побайтового чтения
i=1;
fread(&t,sizeof(t),1,f);
while (!feof(f)){ //Выводим на экран
printf("\n %3d FIO %10s Tel %17s Birthdate %10s", i, t.FIO, t.Tel, t.Date);
fread(&t,sizeof(t),1,f); //Читаем из файла
i++;
}
getch();
}
void app()
/*Начинается самое интересное! Функция добавления записи в начало файла, с использованием временного файла (последовательный доступ)*/
{
FILE *Temp; //Временный файл
Temp=fopen("Temp.dat","wb+"); //Временный файл в режиме записи
char ch;
f=fopen("Data.dat","rb"); //Основной файл в режиме чтения
int i=1;
while (!feof(f)) //Пока основной файл не кончится
fputc(fgetc(f), Temp); //перекладываем содержимое в Temp.
fclose(Temp);
fclose(f);
Temp=fopen("Temp.dat","rb"); //Временный файл в режиме чтения
f=fopen("Data.dat","wb"); //Основной файл в режиме записи
rewind(f); //На всякий случай
rewind(Temp);
do{
system("cls");
printf("\n Input new kontakt\n"); //Читаем структуру с экрана
printf("\n FIO: "); scanf("%s",t.FIO);
printf(" Tel: "); scanf("%s",t.Tel);
printf(" Birthdate: "); scanf("%s",t.Date);
fwrite(&t,sizeof(t),1,f); //Записываем в основной файл
while(!feof(Temp))
fputc(fgetc(Temp), f); //Перекладываем все содержимое
printf(" Exit? y/n "); //временного файла в основной
ch=getch();
}
while (ch != 'y');
fclose(f);
fclose(Temp);
/* Алгоритм очень простой, наглядный. По идее, временный файл после завершения функции нужно удалить, но это мелочи (пока не умею этого делать). Функция работает «на ура», видит конец файла, в общем с режимами последовательного доступа все понятно, проблем не возникало. */
}
void add()
/*Функция добавления записи в начало файла в режиме произвольного доступа. Вот здесь у меня возникли некоторые проблемы. Причем, объективных причин для этого, на мой взгляд, нет. В современной литературе, как правило, отсутствует информация по работе с бинарными файлами, и некоторая схожесть функций с методами класса CFile проблемы не решают. Основная проблема – неясно как ведет себя курсор текущей позиции в файле, при операциях чтения и записи. Дальше по порядку */
{
long i; //Смещение
int kolvo;
char ch;
f=fopen("Data.dat","rb+"); //Режим произвольного доступа
kolvo=0; //Считаем количество записей в файле
while (!feof(f)){
fread(&t,sizeof(t),1,f); //После чтения записи увеличиваем содержимое
kolvo++; //переменной kolvo на единицу
}
/*Вот первая странность: kolvo всегда на единицу больше, чем реальное количество записей в файле. Причем последняя запись читается дважды. В чем проблема непонятно! По этой причине не работает следующий алгоритм:
do{
fread(&t,sizeof(t),1,f); //читаем первую запись в структуру t
while (!feof(f)){
fread(&t1,sizeof(t1),1,f); //читаем текущую запись в t1(еще структура
//типа Kontakt)
i=sizeof(t1);
fseek(f, -i, 1); //назад на sizeof(t1) байт
fwrite(&t,sizeof(t),1,f); //записываем предыдущую запись поверх
//текущей
t=t1; //t1 в t и
getch();// следующая запись
}
По идее здесь должно происходить смещение всех записей на одну позицию вниз. После можно было бы переписать первую запись на новую, и на этом работа закончена, но… Если в файле всего одна запись, то цикл while (!feof(f)) не должен запускаться, поскольку перед ним операцией чтения текущая позиция в файле должна быть установлена на конец файла, но он все равно запускается и зацикливается. Причем зацикливание происходит в любом случае, при любом количестве записей в файле. Даже если заменить fwrite на fread, то цикл будет бесконечное число раз читать последнюю запись. Поэтому так не делаем, делаем так: */
printf(" kolvo=%d ",kolvo);
for (i=(kolvo-2)*sizeof(t);i>=0;i-=sizeof(t)){ /*перебираем записи в файле, начиная с последней */
fseek(f, i, 0); //позицию курсора на текущую запись
fread(&t,sizeof(t),1,f); //читаем текущую запись
fseek(f, i+sizeof(t), 0); /*позицию курсора на следующую за текущей!! Иначе работать не будет!! */
fwrite(&t,sizeof(t),1,f); //Пишем
}
system("cls");
printf("\n Input new kontakt\n"); //Читаем новую структуру
printf("\n FIO: "); scanf("%s",t.FIO);
printf(" Tel: "); scanf("%s",t.Tel);
printf(" Birthdate: "); scanf("%s",t.Date);
fseek(f, 0, 0); //Позицию курсора на начало файла
fwrite(&t,sizeof(t),1,f); //Пишем
printf(" Exit? y/n ");
ch=getch();
while (ch != 'y');
fclose(f);
} //Ура!!! Все работает, но остался неприятный осадок…
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.