Добавил:
Studfiles2
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:
#include "stdafx.h"
#include "algo.h"
const char *TEMP_FILE_F1 = "tempf1.bin";
const char *TEMP_FILE_F2 = "tempf2.bin";
db_algo::db_algo()
{
file1_name = "";
file2_name = "";
file3_name = "";
sred_ball_name = "";
}
// Добавляет в файл temp предмет Name с номером Num
void db_algo::PutF1Temp(int Num, CString &Name, FILE *temp)
{
f1_structure st;
fseek(temp, 0, SEEK_END);
memset(&st, 0, sizeof(st));
st.Nomer = Num;
strcpy(st.Nazvanie, (const char*)Name);
fwrite(&st, sizeof(st), 1, temp);
}
int TestNumStr(const char *str)
{
unsigned int i;
for (i = 0; i < strlen(str); i++)
{
if (str[i] < '0' || str[i] > '9')
{
return 1; // Ошибка
}
}
return 0;
}
// Функция ищет в файле temp (двоичном отражении f1) предмет
// с номером Num и если находит,
// возвращает значание 1, а в переменной Buffer сохраняется
// название предмета. Если не находит, возвращает 0
int db_algo::FindF1Temp(int Num, CString &Buffer, FILE *temp)
{
f1_structure st;
fseek(temp, 0, SEEK_SET);
while (fread(&st, sizeof(st), 1, temp))
{
if (st.Nomer == Num)
{
Buffer = st.Nazvanie;
fseek(temp, 0, SEEK_END);
return 1;
}
}
return 0;
}
// Пишет в двоичный файл temp2 все поля которые есть
// в таблицах 1 и 2
void db_algo::PutF2Temp(int NG, CString &FIO, int NomPr,
CString &NazPr, int Ocenka, FILE *temp2)
{
// Структура для записи во второй временный файл
f2_structure f2_rec;
fseek(temp2, 0, SEEK_END);
memset(&f2_rec, 0, sizeof(f2_rec));
f2_rec.NomerGrup = NG;
strcpy(f2_rec.FIO, (const char*) FIO);
f2_rec.NomerPredmeta = NomPr;
strcpy(f2_rec.NazvaniePredmeta, (const char*) NazPr);
f2_rec.Ocenka = Ocenka;
fwrite(&f2_rec, sizeof(f2_rec), 1, temp2);
}
// Проверяет уникальность ключа первой таблицы, причем одинаковые
// записи в базе допускаются, главное, чтобы соблюдалось правило:
// одному номеру соответствует только один предмет.
// В случае успешного выполения функция создает двоичный
// файл с содержимым первой таблицы, который потребуется
// в дальнейшем
int db_algo::TestUniqID(CString &ErrorMsg)
{
// Указатель на файл базы данных
FILE *MyFile;
FILE *Temp;
// Строка с номером предмета, строка с названием предмета
CString PredmetNumStr, PredmetNameStr;
CString Nazv;
// Строка, прочитанная из файла с базой данных
char DataStr[256];
// Длина строки, прочитанной из файла; Номер предмета
int DataStrLen, PredmetNum;
int i;
// Номер текущего столбца таблицы
int part;
// Номер текущей строки таблицы
int NomerStroki;
// Открыть файл с базой данных как текстовый, в режиме чтения
MyFile = fopen(file1_name, "rt");
if (MyFile == NULL)
{
ErrorMsg.Format("Невозможно открыть файл F1(%s). Проверьте правильность имени \
файла", file1_name);
return 1;
}
// Создать временный файл для чтения-записи
Temp = fopen(TEMP_FILE_F1, "w+b");
if (Temp == NULL)
{
ErrorMsg.Format("Невозможно создать временный файл %s. Проверьте права на \
запись в текущий каталог", TEMP_FILE_F1);
fclose(MyFile);
return 1;
}
NomerStroki = 0;
while (fgets(DataStr, 256, MyFile))
{
NomerStroki++;
DataStr[255] = 0;
if ((DataStrLen = strlen(DataStr)) > 254)
{
ErrorMsg.Format("Превышено максимальное количество символов (254) в строке %d \
файла F1(%s)", NomerStroki, file1_name);
fclose(MyFile);
fclose(Temp);
return 1;
}
PredmetNumStr = "";
PredmetNameStr = "";
part = 1;
for (i = 0; i < DataStrLen; i++)
{
if (DataStr[i] == '\n')
break;
// Символ табуляции означает переход к следующеу столбцу
if (DataStr[i] == '\t')
{
part++;
continue;
}
// Читаем первый столбец
if (part == 1)
PredmetNumStr += DataStr[i];
else
// Читаем второй столбец
if (part == 2)
PredmetNameStr += DataStr[i];
else
{
ErrorMsg.Format("Неверные данные в файле F1(%s). В строке %d содержится \
неверное число полей", file1_name, NomerStroki);
fclose(MyFile);
fclose(Temp);
return 1;
}
}
if (part != 2)
{
ErrorMsg.Format("Неверные данные в файле F1(%s). В строке %d содержится \
неверное число полей", file1_name, NomerStroki);
fclose(MyFile);
fclose(Temp);
return 1;
}
if ((PredmetNameStr.GetLength() == 0) || (PredmetNumStr.GetLength() == 0))
{
ErrorMsg.Format("Неверные данные в файле F1(%s). В строке %d отсутствует одно \
из полей", file1_name, NomerStroki);
fclose(MyFile);
fclose(Temp);
return 1;
}
if (TestNumStr(PredmetNumStr) != 0)
{
ErrorMsg.Format("Ошибка в файле %s, в строке %d. Неверное значание номера \
предмета: \"%s\". Номер предмета должен быть числом.",
file1_name, NomerStroki, PredmetNumStr);
fclose(MyFile);
fclose(Temp);
return 1;
}
// Преобразуем строку PredmetNumStr с изображением числа в само число PredmetNum
sscanf(PredmetNumStr, "%d", &PredmetNum);
if (PredmetNum == 0)
{
ErrorMsg.Format("Ошибка в файле %s, в строке %d. Неверное значание номера \
предмета: \"%s\". Номер предмета не может быть равен нулю.",
file1_name, NomerStroki, PredmetNumStr);
fclose(MyFile);
fclose(Temp);
return 1;
}
// Пробуем найти в уже прочитанных записях (в файле Temp) предмет с
// номером PredmetNum.
// Если это удалось сохраним название предмета в строке Nazv
if (FindF1Temp(PredmetNum, Nazv, Temp))
{
// Предметы с одинаковым номером в базе
ErrorMsg.Format("Ошибка в файле %s, в строке %d. \
Уже определенный номер предмета %d (%s) пытаются определить заново для \
сопоставления с предметом %s.",
file1_name, NomerStroki, PredmetNum, Nazv, PredmetNameStr);
fclose(MyFile);
fclose(Temp);
return 1;
}
else
{
PutF1Temp(PredmetNum, PredmetNameStr, Temp);
}
}
fclose(MyFile);
fclose(Temp);
return 0;
}
int db_algo::MakeBinResTable(CString &ErrorMsg)
{
// Текстовый файл со 2-й таблицей
FILE *File2;
// Указатель на двоичный файл c результатом обработки таблиц
FILE *Temp2;
// Временный файл с двоичными данными первой таблицы
FILE *Temp1;
// Поля таблицы в строковом представлении
CString NomerGrupStr, FIOStr, NomerPredmetaStr, OcenkaStr, NazvaniePredmeta;
int NomerGrup, NomerPredmeta, Ocenka;
// Строка, прочитанная из файла с базой данных
char DataStr[256];
// Длина строки, прочитанной из файла
int DataStrLen;
int i;
// Номер текущего столбца таблицы
int part;
// Номер текущей строки таблицы
int NomerStroki;
// Открыть файл с базой данных как текстовый, в режиме чтения
File2 = fopen(file2_name, "rt");
if (File2 == NULL)
{
ErrorMsg.Format("Невозможно открыть файл F2(%s). Проверьте правильность имени \
файла", file2_name);
return 1;
}
// Создать временный файл для чтения-записи
Temp2 = fopen(TEMP_FILE_F2, "w+b");
if (Temp2 == NULL)
{
ErrorMsg.Format("Невозможно создать временный файл %s. Проверьте права на \
запись в текущий каталог", TEMP_FILE_F2);
fclose(File2);
return 1;
}
// Открыть временный файл, созданный на предыдущем этапе
Temp1 = fopen(TEMP_FILE_F1, "rb");
if (Temp1 == NULL)
{
ErrorMsg.Format("Невозможно открыть временный файл %s. Проверьте права на \
запись в текущий каталог", TEMP_FILE_F1);
fclose(File2);
fclose(Temp2);
return 1;
}
NomerStroki = 0;
while (fgets(DataStr, 256, File2))
{
NomerStroki++;
DataStr[255] = 0;
if ((DataStrLen = strlen(DataStr)) > 254)
{
ErrorMsg.Format("Превышено максимальное количество символов (254) в строке %d \
файла F2(%s)", NomerStroki, file2_name);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
NomerGrupStr = "";
FIOStr = "";
NomerPredmetaStr = "";
OcenkaStr = "";
part = 1;
for (i = 0; i < DataStrLen; i++)
{
if (DataStr[i] == '\n')
break;
// Символ табуляции означает переход к следующеу столбцу
if (DataStr[i] == '\t')
{
part++;
continue;
}
// Читаем первый столбец
if (part == 1)
NomerGrupStr += DataStr[i];
else
// Читаем второй столбец
if (part == 2)
FIOStr += DataStr[i];
else
if (part == 3)
NomerPredmetaStr += DataStr[i];
else
if (part == 4)
OcenkaStr += DataStr[i];
else
{
ErrorMsg.Format("Неверные данные в файле F2(%s). В строке %d содержится \
неверное число полей",
file2_name, NomerStroki);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
}
// Если прочитано не 4-ре столбца
if (part != 4)
{
ErrorMsg.Format("Неверные данные в файле F2(%s). В строке %d содержится \
неверное число полей", file2_name, NomerStroki);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
if ((NomerGrupStr.GetLength() == 0) || (FIOStr.GetLength() == 0) ||
(NomerPredmetaStr.GetLength() == 0) || (OcenkaStr.GetLength() == 0))
{
ErrorMsg.Format("Неверные данные в файле F2(%s). В строке %d отсутствует одно \
из полей", file2_name, NomerStroki);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
if (TestNumStr(NomerGrupStr) != 0)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d. Неверное значание номера \
группы: \"%s\". Номер группы должен быть числом.",
file2_name, NomerStroki, NomerGrupStr);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
sscanf(NomerGrupStr, "%d", &NomerGrup);
if (NomerGrup == 0)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d. Неверное значание номера \
группы: \"%s\". Номер группы не может быть равен нулю.",
file2_name, NomerStroki, NomerGrupStr);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
if (TestNumStr(NomerPredmetaStr) != 0)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d. Неверное значание номера \
предмета: \"%s\". Номер предмета должен быть числом.",
file2_name, NomerStroki, NomerPredmetaStr);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
sscanf(NomerPredmetaStr, "%d", &NomerPredmeta);
if (NomerPredmeta == 0)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d. Неверное значание номера \
предмета: \"%s\". Номер предмета не может быть равен нулю.",
file2_name, NomerStroki, NomerPredmetaStr);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
if (TestNumStr(OcenkaStr) != 0)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d. Неверное значание оценки \
\"%s\". Оценка должна быть числом.",
file2_name, NomerStroki, OcenkaStr);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
sscanf(OcenkaStr, "%d", &Ocenka);
if (Ocenka < 2 || Ocenka > 5)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d. Неверное значение оценки: \
\"%s\". Оценка должна быть от 2 до 5.",
file2_name, NomerStroki, OcenkaStr);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
if (FindF1Temp(NomerPredmeta, NazvaniePredmeta, Temp1) == 0)
{
ErrorMsg.Format("Ошибка в файле F2(%s), в строке %d указан несуществующий \
номер предмета %d",
file2_name, NomerStroki, NomerPredmeta);
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 1;
}
PutF2Temp(NomerGrup, FIOStr, NomerPredmeta, NazvaniePredmeta, Ocenka, Temp2);
} // while
fclose(File2);
fclose(Temp2);
fclose(Temp1);
return 0;
}
void db_algo::SetFileNames(CString f1_name, CString f2_name, CString f3_name,
CString sr_ball)
{
file1_name = f1_name;
file2_name = f2_name;
file3_name = f3_name;
sred_ball_name = sr_ball;
}
void db_algo::SetSredniBallFileName(CString sr_ball)
{
sred_ball_name = sr_ball;
}
// Ищет первыю непомеченную запись во временном файле f2
// и копирует ее в область памяти, на которую ссылается st.
// Помечает эту запись и возвращает обратно в этот же файл,
// так что при следующем обращении вернется следующая запись
int db_algo::GetFirstUnmarketRecord(f2_structure &st, FILE *f2)
{
f2_structure rec;
unsigned int pos = 0;
fseek(f2, 0, SEEK_SET);
while (fread(&rec, sizeof(rec), 1, f2) != 0)
{
pos++;
if (rec._metka == 0)
{
rec._metka = 1;
fseek(f2, (pos - 1) * sizeof(rec), SEEK_SET);
fwrite(&rec, sizeof(rec), 1, f2);
memcpy(&st, &rec, sizeof(rec));
return 1;
}
}
return 0;
}
// Записывает строку в третий файл f3 (в текстовом формате)
void db_algo::PutRecordF3(f2_structure &st, FILE *f3)
{
char ResStr[536];
sprintf(ResStr, "%d\t%s\t%s\t%d\n", st.NomerGrup,
st.NazvaniePredmeta, st.FIO, st.Ocenka);
fputs(ResStr, f3);
}
// Ищет первую непомеченную запись в файле f2 с номером предмета NP и номером
// группы NG, записывет содержимое этой записи в область памяти, куда
// ссылается st и помечает в файле что эта запись помечена (т. е. при следующем
// вызове этой функции будет найдена следующая запись). Если уже
// больше ничего нет, то вернет 0
int db_algo::GetFindUnmarket(int NP, int NG, f2_structure &st, FILE *f2)
{
f2_structure rec;
unsigned int pos = 0;
fseek(f2, 0, SEEK_SET);
while (fread(&rec, sizeof(rec), 1, f2) != 0)
{
pos++;
if (rec._metka == 0 && rec.NomerPredmeta == NP && rec.NomerGrup == NG)
{
rec._metka = 1;
fseek(f2, (pos - 1) * sizeof(rec), SEEK_SET);
fwrite(&rec, sizeof(rec), 1, f2);
memcpy(&st, &rec, sizeof(rec));
return 1;
}
}
return 0;
}
// Генерирует текстовый файл f3
int db_algo::GenF3(CString &ErrorMsg)
{
// Файл Temp2 содержит объедененную таблицу
FILE *Temp2;
// Текстовый файл с результирующей таблицей
FILE *f3;
f2_structure f2s1, f2s2;
f3 = fopen(file3_name, "wt");
if (f3 == NULL)
{
ErrorMsg.Format("Не удалось создать файл F3(%s), проверьте наличие прав \
на запись в данный файл.", file3_name);
return 1;
}
Temp2 = fopen(TEMP_FILE_F2, "r+b");
if (Temp2 == NULL)
{
ErrorMsg.Format("Не удалось открыть временный файл %s для чтения-записи.",
TEMP_FILE_F2);
fclose(f3);
return 1;
}
while (GetFirstUnmarketRecord(f2s1, Temp2) != 0)
{
PutRecordF3(f2s1, f3);
while (GetFindUnmarket(f2s1.NomerPredmeta, f2s1.NomerGrup, f2s2, Temp2) != 0)
{
PutRecordF3(f2s2, f3);
}
}
fclose(f3);
fclose(Temp2);
return 0;
}
int db_algo::CalculeSredBall(CString &ErrorMsg)
{
FILE *sbf;
FILE *Temp2;
f2_structure buff1, buff2;
int summa_ocenok, kolvo_ocenok;
double sredni_ball;
sbf = fopen(sred_ball_name, "w");
if (sbf == NULL)
{
ErrorMsg.Format("Ошибка. Невозможно создать файл %s.", sred_ball_name);
return 1;
}
Temp2 = fopen(TEMP_FILE_F2, "r+b");
if (Temp2 == NULL)
{
ErrorMsg.Format("Невозможно открыть временный файл для чтения-записи %s",
TEMP_FILE_F2);
fclose(sbf);
return 1;
}
DeleteAllMetka(Temp2);
summa_ocenok = 0;
kolvo_ocenok = 0;
while (GetFirstUnmarketRecord(buff1, Temp2) != 0)
{
summa_ocenok += buff1.Ocenka;
kolvo_ocenok++;
while (GetFindUnmarket(buff1.NomerPredmeta, buff1.NomerGrup, buff2, Temp2) != 0)
{
summa_ocenok += buff2.Ocenka;
kolvo_ocenok++;
}
sredni_ball = (double)summa_ocenok / kolvo_ocenok;
summa_ocenok = 0;
kolvo_ocenok = 0;
PutSredniBall(buff1.NomerGrup, buff1.NazvaniePredmeta, sredni_ball, sbf);
}
fclose(sbf);
fclose(Temp2);
return 0;
}
void db_algo::DeleteAllMetka(FILE *f2)
{
f2_structure buff;
long pos;
fseek(f2, 0, SEEK_SET);
pos = 0;
while (fread(&buff, sizeof(buff), 1, f2))
{
// После прочтения записи текущая позиция в файле
// перешла к следующей записи, вернемся к началу
// прочитанной записи
fseek(f2, ++pos * sizeof(buff), SEEK_SET);
buff._metka = 0; // Снять метку
// Запишем модифицированную запись поверх себя
fwrite(&buff, sizeof(buff), 1, f2);
fflush(f2);
}
}
void db_algo::PutSredniBall(int NomGr, const char* NazPr, double SrBall, FILE *fballs)
{
char string_data[512];
sprintf(string_data, "Группа номер %d по предмету %s имеет средний балл %.6f\n",
NomGr, NazPr, SrBall);
fputs(string_data, fballs);
}