Скачиваний:
21
Добавлен:
02.05.2014
Размер:
17.28 Кб
Скачать
#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);
}
Соседние файлы в папке Курсовой - Специфицирование и тестирование программ2