ShineWithMe 2008. 9. 2. 15:43

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class node // 링크리스트 노드 클래스
{ // friend class로 StudentRecord 설정
 friend class StudentRecord;
public:
 int sno;
 string sname;
 float score;
 node *link;
};

node *ptr; // 리스트 root

class StudentRecord
{
private:
 int sno;
 string sname;
 float score;

public:
 StudentRecord()
 { // 노드의 초기화
  ptr = new node;
  ptr->sno = 0;
  ptr->sname = "";
  ptr->score = 0;
  ptr->link = NULL;
 }

 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(ifstream&); // 파일에서 읽는 함수
 void printRecord(ostream&); // 레코드 출력 함수
 bool operator== (StudentRecord s); // operator == 재정의 함수
 void addback(); // 리스트 맨뒤에 새노드추가 함수
};


bool is_NodeNull(node *p1) // 노드가 NULL인지 검사 함수
{
 if(p1->sno==0 && p1->sname =="" && p1->score == 0)
  return false;
 else
  return true;
}

void exchange(node *x, node *y) // 노드값 교환 함수
{        
 node* temp = new node;
 // 다음노드의 포인터를 제외한 나머지 교환
 temp->sno = x->sno;
 temp->sname = x->sname;
 temp->score = x->score;
 x->sno = y->sno;
 x->sname = y->sname;
 x->score = y->score;
 y->sno = temp->sno;
 y->sname = temp->sname;
 y->score = temp->score;
}

void bubble(node *p) // 리스트 정렬
{
 node *q = new node;
 q = p;
 while (q)
 {
  node *p1 = new node;
  *p1 = *q;
  while(p1)
  {
   if(p1->sno < q->sno)
    exchange(p1, q);
   p1 = p1->link;
  }
  delete p1;
 q = q->link;
 }
 p = q;
 delete q;
}


bool StudentRecord::operator== (StudentRecord s) // == 연산자 재정의
{
 if(this->sno==s.sno && this->sname==s.sname && this->score==s.score)
  return true;
 else
  return false;
}

void StudentRecord::readFromFile(ifstream& Bin)// 이진파일 읽기
{
 int len;
 char* name = new char[20];
 Bin.read((char*) &sno, sizeof(int));
 Bin.read((char*) &len, sizeof(int));
 Bin.read((char*) name, (std::streamsize)len);
 name[len] = '\0';
 sname = name;
 Bin.read((char*) &score, sizeof(float));
}

void StudentRecord::addback()
{ // 새 레코드를 리스트 맨뒤에 추가
 node *pt = new node;
 node *temp = new node;
 pt = ptr;

 temp->sno = this->sno;
 temp->sname = this->sname;
 temp->score = this->score;
 // 리스트의root인 ptr에 값이 있는지
 // 검사해 있으면 없을때 까지 리스트
 // 하위로 내려가 끝에 새노드 추가
 if(is_NodeNull(ptr))
 {
  while(pt->link)
  {
   pt = pt->link;
  }

  temp->link = NULL;
  pt->link = temp;
 }
 else
 {
  temp->link = NULL;
  ptr = temp;
 }
}
 
void printList(node *ptr)// 리스트를 화면에 출력
{
 node *p1;
 p1 = ptr;
 while(p1)
 {
  cout << p1->sno <<'\t'<< p1->sname <<'\t'<< p1->score <<endl;
  p1 = p1->link;
 }

}

float average(node *ptr)// 리스트의 score들의 평균
{
 node *p1;
 p1 = ptr;
 int cnt=0;
 float average=0;
 while(p1)
 {
  average += p1->score;
  p1 = p1->link;
  cnt++;
 }
 return average/cnt;

}

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


void writeToFile(ofstream& BinOut, node *ptr)// 리스트를 이진파일에 쓰기
{
 node *p1; // 임시노드
 p1 = ptr;
 while(p1)
 {
  // 채워야 할 부분
  int namelen = (int)p1->sname.length();
  BinOut.write((char*) &p1->sno, sizeof(int));
  BinOut.write((char*) &namelen, sizeof(int));
  BinOut.write(p1->sname.c_str(), (std::streamsize)namelen);
  BinOut.write((char*) &p1->score, sizeof(float));
  p1 = p1->link; // 다음 노드
 }
}


int main(int argc, char* argv[])
{
 StudentRecord S, R; // 임시 저장 레코드 S, R

 ifstream BinStudent(argv[1], ios::binary); // 파일열기
 ofstream Binout("output.bin", ios::binary);

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

 while (BinStudent.peek() != EOF) // 파일을 임시 레코드로 읽어
 {         // 임시레코드를 리스트에 추가
  S.readFromFile(BinStudent);
  S.addback();
 }

 bubble(ptr); // 리스트 정렬
 cout << "-----Sorted List(origin:student.bin)-----" << endl;
 cout << "[Num.]\t[Name]\t\t[Score]"<< endl;
 printList(ptr); // 리스트 화면 출력
 cout << "# Average Score : " << average(ptr) << endl; // 평균 화면 출력
 
 writeToFile(Binout, ptr); // 리스트 파일 출력

 Binout.close(); // output.bin 파일 ifstream으로 다시열기
 ifstream BinStudentSorted("output.bin", ios::binary);

 BinStudent.clear(); // 파일객체 리프래쉬
 BinStudent.seekg(0, ios::beg);
 BinStudentSorted.clear();
 BinStudentSorted.seekg(0, ios::beg);

 bool bc = true; // flag

 int findex = 0, sindex = 0; // 레코드 수를 저장할 변수
 while (BinStudent.peek() != EOF)
 {
  S.readFromFile(BinStudent);
  findex++; //첫번째 파일의 레코드수
 }
 while (BinStudentSorted.peek() != EOF)
 {
  R.readFromFile(BinStudentSorted);
  sindex++; //두번째 파일의 레코드수
 }

 //레코드 수검사
 cout << "\n파일 일치하는가?" << endl;
 if(findex != sindex)
 {
  cout << " 파일이 다릅니다.\n" << endl;

  BinStudent.clear(); // 파일객체 리프래쉬
  BinStudentSorted.clear();
  BinStudent.seekg(0, ios::beg);
  BinStudentSorted.seekg(0, ios::beg);

  cout << "student.bin " << endl; // 화면출력
  cout << "[Num.]\t[Name]\t\t[Score]"<< endl;
  while (BinStudent.peek() != EOF)
  {
   S.readFromFile(BinStudent);
   S.printRecord(cout);
  }

  cout << endl << "output.bin" << endl;
  cout << "[Num.]\t[Name]\t\t[Score]"<< endl;
  while (BinStudentSorted.peek() != EOF)
  {
   R.readFromFile(BinStudentSorted);
   R.printRecord(cout);
  }
  return 0;
 }


 // 레코드 내용이 같으지 검사
 while (BinStudent.peek() != EOF)
 {
  S.readFromFile(BinStudent);
  while(BinStudentSorted.peek() != EOF)
  {
   R.readFromFile(BinStudentSorted);
  if(S==R) // 두 레코드가 같은지 검사
   bc = true; // flag 에 true
  else
   bc = false; // flag 에 false
  }
 }

 //결과 출력
 if(bc==true) // flag가 true이면 같고 flase면 다르므로
 {    // 두파일의 일치여부와 내용을 화면출력
  cout << " \n\n  파일이 같습니다. \n\n" << endl;

  BinStudent.clear();
  BinStudentSorted.clear();
  BinStudent.seekg(0, ios::beg);
  BinStudentSorted.seekg(0, ios::beg);

  cout << "-----student.bin----- " << endl;
  cout << "[Num.]\t[Name]\t\t[Score]"<< endl;
  while (BinStudent.peek() != EOF)
  {
   S.readFromFile(BinStudent);
   S.printRecord(cout);
  }

  cout << endl << "-----output.bin-----" << endl;
  cout << "[Num.]\t[Name]\t\t[Score]"<< endl;
  while (BinStudentSorted.peek() != EOF)
  {
   R.readFromFile(BinStudentSorted);
   R.printRecord(cout);
  }
 }
 else
 {
  cout << " \n\n파일이 다릅니다.\n\n" << endl;

  BinStudent.clear();
  BinStudentSorted.clear();
  BinStudent.seekg(0, ios::beg);
  BinStudentSorted.seekg(0, ios::beg);

  cout << "-----student.bin-----" << endl;
  while (BinStudent.peek() != EOF)
  {
   S.readFromFile(BinStudent);
   S.printRecord(cout);
  }

  cout << endl << "-----output.bin-----" << endl;
  while (BinStudentSorted.peek() != EOF)
  {
   R.readFromFile(BinStudentSorted);
   R.printRecord(cout);
  }
  return 0;
 }

 BinStudent.close(); // 파일 닫기
 BinStudentSorted.close();

 return 0;
}