정리필요2

파일처리 실습9

ShineWithMe 2008. 9. 1. 23:09

#include <iostream>
#include <fstream>
#include <string>
using namespace std;
#define COMPARE(x, y) (((x)<(y)) ? -1:((x)==(y)) ? 0:1)
const int MAXNAME = 20;
const int MAXSIZE = 10;

class StudentRecord
{
private:
 int sno;
 string sname;
 float score;
public:
 StudentRecord() {;}
 StudentRecord(int no, string name, float s) {sno=no, sname=name, score=s;}
 void setSno(int no) {sno = no;}
 void setSname(string name) {sname = name;}
 void setScore(float s) {score = s;}
 int getSno() const {return sno;}
 string getSname() const {return sname;}
 float getScore() const {return score;}
 void readFromFile(fstream&);
 void writeToFile(fstream&);
 void printRecord(ostream&);
 int size();
};
void StudentRecord::writeToFile(fstream& BinOut)// 이진파일에 쓰기
{
 BinOut.write((char*) &sno, sizeof(int));  // 4
 BinOut.write(sname.c_str(), MAXNAME);   // 20
 BinOut.write((char*) &score, sizeof(float));   // 4
}

void StudentRecord::readFromFile(fstream& Bin)// 이진파일 읽기
{
 // 가변길이로
 Bin.read((char*) &sno, sizeof(int));  // 4
 char *name = new char[MAXNAME];
 Bin.read((char*) name, MAXNAME);   // 20
 //name[MAXNAME-1] = '\0';
 sname = name;
 Bin.read((char*) &score, sizeof(float)); // 4
}

void StudentRecord::printRecord(ostream&)// 화면에 출력
{
 // 채워야 할 부분
 cout << sno <<'\t'<< sname <<'\t'<< score <<endl;
}

int StudentRecord::size()
{
 return sizeof(sno) + MAXNAME + sizeof(score);
}

/*
class KeyIndex
{
private:
 int key;
 //int Offset;
 int RRN;
public:
 KeyIndex() {;}
 KeyIndex(int k, int r) {key = k, RRN = r;}
 void Set(int k, int r) {key = k, RRN = r;}
 int getKey() const {return key;}
 int getRRN() const {return RRN;}
 void readFromFile(fstream& Bin);
};
void KeyIndex::readFromFile(fstream& Bin)// 이진파일 읽기
{
 Bin.read((char*) &key, sizeof(int));  // 4
 Bin.read((char*) &RRN, sizeof(int));  // 4
}
*/

template <class Type>
class Sort
{
private:
 void exchange(Type &a, Type &b);
public:
 void bubble(StudentRecord *data, int n);
};

template <class Type> //버블소트로 인덱스정렬
void Sort<Type>::bubble(StudentRecord *data, int n)
{

 int i=0, j=0;
  for(i=0; i<n; i++)
   for(j=0; j<n; j++)
    if(data[i].getSno() < data[j].getSno())
     exchange(data[i], data[j]);
}

template <class Type> // 교환함수
void Sort<Type>::exchange(Type &a, Type &b)
{
 Type c;
 c=a;
 a=b;
 b=c;
}

class DataFile
{
private:
 fstream* database;  // 저장된 데이터 파일에 대한 포인터
 int numRecord;   // 레코드 수
public:
 DataFile() {database, numRecord = 0;}
 ~DataFile() {database->close();}
 void setDataFile(fstream& fs, int num) {database = &fs, numRecord = num;}
 void insert(StudentRecord rec);
 bool search(int sno);
 void printFile();
 void shiftRecord(int startRRN); // startRRN 위치부터 끝까지 한 레코드씩 이동
 void readByRRN(int RRN, StudentRecord& rec); // RRN에 위치한 레코드를 읽어옴
 void writeByRRN(int RRN, StudentRecord rec); // RRN 위치에  레코드 rec를 씀 
 void showRRNandOffset();
};

void DataFile::printFile()
{

 if(!database->is_open())
 {
  cout << "file open fail" << endl;
  return;
 }

 database->clear();
 database->seekg(0, ios::beg);

 StudentRecord temp;
 for(int i=0; i<numRecord; i++)
 {
  temp.readFromFile(*database);
  temp.printRecord(cout);
 }
}

void DataFile::showRRNandOffset()
{
 database->clear();
 database->seekg(0, ios::beg);

 StudentRecord temp;
 for(int i=0; i<numRecord; i++)
 {
  cout<< "RRN :" << i << ", Offset :" << database->tellg() << endl;
  temp.readFromFile(*database);
 
 }
}

void DataFile::insert(StudentRecord rec)
{
 database->clear();
 database->seekg(0, ios::beg);

 StudentRecord *T = new StudentRecord[numRecord];
 for(int i=0; i<numRecord; i++)
  T[i].readFromFile(*database);

 if(rec.getSno() < T[0].getSno())
 {
  shiftRecord(0);
  writeByRRN(0, rec);
  numRecord++;
 }
 else if(rec.getSno() > T[numRecord-1].getSno())
 {
  writeByRRN(numRecord, rec);
  numRecord++;
 }
 else{
  for(int i=0; i<numRecord-2; i++)
  {
   if(rec.getSno() > T[i].getSno() && rec.getSno() < T[i+1].getSno())
   {
    shiftRecord(i);
    writeByRRN(i, rec);
    numRecord++;
   }
  }
 }
}

void DataFile::shiftRecord(int startRRN)
{
 StudentRecord temp;
 int point = numRecord-1;
 database->clear();
 for(int i=0; point>=startRRN; point--)
 {
  readByRRN(point, temp);
  writeByRRN(point+1, temp);
 }
}

void DataFile::readByRRN(int RRN, StudentRecord& rec)
{
 database->seekg(RRN*rec.size(), ios::beg);
 rec.readFromFile(*database);
}

void DataFile::writeByRRN(int RRN, StudentRecord rec)
{
 database->seekg(RRN*rec.size(), ios::beg);
 rec.writeToFile(*database);
}

bool DataFile::search(int sno)
{
 database->clear();
 database->seekg(0, ios::beg);

 StudentRecord *R = new StudentRecord[numRecord];
 for(int i=0; i<numRecord; i++)
  R[i].readFromFile(*database);

 int middle, left, right;
 int RRN=0;

 left=0;
 right=numRecord-1;
 
 while(left <= right)
 {
  middle = (left+right)/2;
  switch (COMPARE(R[middle].getSno(), sno))
  {
  case -1 : left = middle + 1;
   break;
  case 0 :
   cout<< "The student is in the database."<< endl;
   R[middle].printRecord(cout);
   return true; 
  case 1 : right = middle - 1;
  }
 }
 cout << "The student is not in the database."<< endl;
 return false;
}

int main(int argc, char* argv[])
{
 StudentRecord S[MAXSIZE], R;

 char sname[MAXNAME]; // 레코드저장할임시변수
 int sno;
 float score;

 ifstream textin(argv[1]);

 if(!textin.is_open())
 {
  cout << "파일을 열수 없습니다. " << endl;
  return 0;
 }

 int i=0, n=0;
 // student 파일에서 레코드 읽어 배열에 저장
 while (textin.good() && textin.peek() != EOF)
 {
  textin >> sno >> sname >> score;
  textin.ignore(300, '\n');
  S[i] = StudentRecord(sno, sname, score);
  i++;
 }

 int numRecord = i; // 레코드 갯수
 
 fstream BinFile("student.bin", ios::in | ios::out | ios::trunc | ios::binary);
 
 // 배열에 있는 레코드를 정렬
 Sort<StudentRecord> sort;
 sort.bubble(S, numRecord);

 // 이진파일 생성
 for(int j=0; j<numRecord; j++)
  S[j].writeToFile(BinFile); // 이진파일에 쓰기
 
 // 이진파일 시험출력
 BinFile.clear();
 BinFile.seekg(0, ios::beg);
 for (int n=0; n<numRecord; n++)
 {
  R.readFromFile(BinFile);
  R.printRecord(cout);
 }
 
 DataFile d;
 d.setDataFile(BinFile, numRecord);
 
/*
 StudentRecord N = StudentRecord(2002158, "KyungKyusung", 99.90);
 d.insert(N);
 d.showRRNandOffset();
 cout << endl;
 d.printFile();
*/

 int key;
 StudentRecord s;
 char command;
 cout << "Enter a choice: 1. Insert, 2. Search, 3. Print, 4. Exit:";
 cin >> command;
 

 while (command != '4')
 {
  switch(command)
  {
  case '1': // insert
  cout << "Enter a record : sno sname score :";
  cin >> sno >> sname >> score;
  s = StudentRecord(sno, sname, score);
  d.insert(s);
  break;
 
  case '2':
  cout << "Enter a student number:";
  cin >> key;
  d.search(key);
  break;

  case '3':
  d.printFile();
  break;

  default : break;
  }
  cout << "Enter a choice: 1. Insert, 2. Search, 3. Print, 4. Exit:";
  cin >> command;
 }

 return 0;
}