파일처리
by 오민#define _CRT_SECURE_NO_WARNINGS //visual studio에서 scanf를 사용할때 발생하는 오류를 무시하기 위한 명령어
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void insert(FILE *f);
void bulk_insert(FILE *f);
void search_name(FILE *f);
void search_range(FILE *f);
void display_total(FILE *f);
void display_single(FILE *f);
void printhead();
void update(FILE *f);
void del(FILE *f);
void removal(FILE *f);
void grade(FILE *f);
typedef struct student
{
int num;
char name[20];
int mid;
int final;
int quiz;
} student;
//구조체 형식 선언. dypedef struct student를 student라고 쓰겠다는 것이다.
//구조체의 형식만 지정해주었으니 해당 구조체를 쓰기 위해선 사용할 때 구조체를 선언해줘야 한다.
long int studsize = (long)sizeof(student);
//원래 studsize은 long int에 해당하기 때문에 int 앞에 long을 붙여줘야 한다.
//하지만 vs code에서는 붙여주지 않아도 잘 작동한다.
int main()
{
char fname[] = "student.bin";
//이진파일의 이름을 변수에 담았다. 귀찮음을 덜기 위함이다.
//이진파일이 텍스트 파일보다 용량도 적고 빠르다.
FILE *f; //파일포인터 변수 선언.이제 파일을 열고 파일주소를 해당 파일포인터에 저장할 수 있다.
char option = 0;
if ((f = fopen(fname, "rb+")) == NULL)
{ //파일을 열어서 포인터에 담고, 제대로 담겼는지 확인을 하기 위해 null과 비교를 한다.
if ((f = fopen(fname, "wb+")) == NULL)
{
printf("파일이 열리지 않습니다\n");
exit(1); //메인함수에서의 return과 동일한 기능을 하는 함수. 다만 stdlib.h이 있어야 작동한다.
}
/*
"r" : 읽기. 파일 없으면 에러.
“w” : 덮어쓰기. 없으면 만듦.
“a” : 파일끝에서쓰기. 없으면 만듦.
“r+” : 읽고쓰기. 없으면 에러.
“w+” : 읽고쓰기. 없으면 만듦.
“a+” : 파일끝에서읽고쓰기. 없으면 만듦.
t : text, b : binary. 아무것도 없으면 기본으로 t모드.
*/
}
while (1)
{
if (option != '\n')
printf("전체정보출력(t), 탐색(s),이름 탐색(n),범위탐색(q),입력(i),대량삽입(b).수정(u),삭제(d),전체삭제(r),성적처리(g),종료(f)를 선택하세요:");
scanf("%c", &option);
fflush(stdin); //표준입력스트림 버퍼를 비워준다. vs의 경우 작동안하는 버전도 있다고 한다.
switch (option)
{
case 't':
display_total(f);
break;
case 's':
display_single(f);
break;
case 'n':
search_name(f);
break;
case 'q':
search_range(f);
break;
case 'i':
insert(f);
break;
case 'b':
bulk_insert(f);
break;
case 'u':
update(f);
break;
case 'd':
del(f);
break;
case 'r':
removal(f);
break;
case 'g':
grade(f);
break;
case 'f':
break;
}
if (option == 'f')
break;
}
fclose(f);
return 0;
}
void display_total(FILE *f) //전체 정보 출력
{
rewind(f); //position indicator 위치 초기화
student stud; //구조체를 사용하기위해 변수를 선언해준다.
int cnt = 0;
fread(&stud, studsize, 1, f); //한명이라도 있는지 확인하려고 미리 한명의 정보를 읽어온다.
printhead();
if (stud.num) //stud.num에 든 수가 0이 아닐때
{
while (!feof(f))
{ //feof함수는 스트림(f)의 위치 지정자 (position indicator)가 파일의 끝에 있으면 0이 아닌 값을 출력한다.
fprintf(stdout, "%6d%18s%8d%8d%8d\n", stud.num, stud.name, stud.mid, stud.final, stud.quiz);
//fprintf(stdout,)는 printf()와 같은 의미
fread(&stud, studsize, 1, f); //f에서 구조체 크기로 1개를 읽어서 stud에 담기.
cnt++;
}
}
printf("-----------------------------------------\n");
printf("모두 %d명 입니다\n", cnt);
}
void search_range(FILE *f)
{
rewind(f);
student stud;
char minname[30];
char maxname[30];
int cnt = 0;
printf("탐색할 이름의 최솟값을 입력하세요(가나다순):");
scanf("%s", minname);
printf("탐색할 이름의 최댓값을 입력하세요(가나다순):");
scanf("%s", maxname);
printhead();
while (!feof(f))
{
fread(&stud, studsize, 1, f);
if (strcmp(stud.name, minname) >= 0 && strcmp(stud.name, maxname) <= 0)
{
printf("%6d%18s%8d%8d%8d\n", stud.num, stud.name, stud.mid, stud.final, stud.quiz);
cnt++;
}
}
printf("-----------------------------------------\n");
printf("모두 %d명 입니다\n", cnt);
}
void search_name(FILE *f)
{
rewind(f);
student stud;
char name[30];
int cnt = 0;
printf("탐색할 이름을 입력하세요:");
scanf("%s", name);
printhead();
while (!feof(f))
{
fread(&stud, studsize, 1, f);
if (strcmp(stud.name, name) == 0)
{
fprintf(stdout, "%6d%18s%8d%8d%8d\n", stud.num, stud.name, stud.mid, stud.final, stud.quiz);
cnt++;
}
}
printf("-----------------------------------------\n");
printf("모두 %d명 입니다\n", cnt);
}
void insert(FILE *f) //입력,추가
{
student stud = {0};
char line[50];
if ((f = fopen("student.bin", "ab+")) == NULL)
{
printf("파일이 열리지 않습니다\n");
exit(1);
}
fread(&stud, studsize, 1, f);
if (stud.num)
{
fseek(f, -studsize, SEEK_END);
fread(&stud, studsize, 1, f); //여기서 어차피 위치 지정자가 파일의 끝에 위치할텐데
fseek(f, 0L, SEEK_END); //이 문장이 불필요한 것 같은데 지우면 에러가 난다. vs에서는 지워도 잘 작동을 한다.
} //long과 int의 차이 때문에 발생하는 오류정도로 예상된다.
printf("이름과 성적(중간,기말,퀴즈)을 입력하세요\n");
fgets(line, 50, stdin);
sscanf(line, "%s %d %d %d", stud.name, &stud.mid, &stud.final, &stud.quiz);
stud.num++;
fwrite(&stud, studsize, 1, f);
fclose(f);
}
void bulk_insert(FILE *f)
{
student stud = {0};
char line[50];
if ((f = fopen("student.bin", "ab+")) == NULL)
{
printf("파일이 열리지 않습니다\n");
exit(1);
}
fread(&stud, studsize, 1, f);
if (stud.num)
{
fseek(f, -studsize, SEEK_END);
fread(&stud, studsize, 1, f);
fseek(f, 0L, SEEK_END); //중간 값이 0이 아니라 0L인 것도 (long)int 0을 의미하는 것이다.
} //마지막 학생의 stud.num값을 구하기 위한 과정.
rewind(stdin);
while (1)
{
printf("추가할 정보:");
fgets(line, 50, stdin);
if (feof(stdin))
break;
sscanf(line, "%s %d %d %d", stud.name, &stud.mid, &stud.final, &stud.quiz);
stud.num++;
fwrite(&stud, studsize, 1, f); //stud에 든 정보를 f 스트림에 한번 작성하겠다.
} //성공시 1(한 번)반환, 실패시 1보다 작은 수 반환.
fclose(f);
}
void display_single(FILE *f) // 탐색
{
student s1;
int search = 0;
printf("탐색할 정보의 번호를 입력하세요:");
scanf("%d", &search);
fseek(f, studsize * (search - 1), SEEK_SET);
fread(&s1, studsize, 1, f);
printf("%d번의 정보: (%s,%d,%d,%d)\n", search, s1.name, s1.mid, s1.final, s1.quiz);
}
void update(FILE *f)
{
int i = 0;
int fix = 0;
student stud;
printf("수정할 정보의 번호를 입력하세요:");
scanf("%d", &fix);
fseek(f, studsize * (fix - 1), SEEK_SET);
fread(&stud, studsize, 1, f);
printf("%d번의 정보: (%s,%d,%d,%d)\n", stud.num, stud.name, stud.mid, stud.final, stud.quiz);
printf("수정할 내용:");
scanf("%s %d %d %d", stud.name, &stud.mid, &stud.final, &stud.quiz);
fseek(f, studsize * (fix - 1), SEEK_SET);
fwrite(&stud, studsize, 1, f);
}
void del(FILE *f)
{
rewind(f);
int delnum = 0, num = 0;
student stud[30];
printf("삭제할 정보의 번호를 입력하세요:");
while (!feof(f))
fread(&stud[++num], studsize, 1, f);
num--;
scanf("%d", &delnum);
printf("%d번의 정보: (%s,%d,%d,%d)\n", stud[delnum].num, stud[delnum].name, stud[delnum].mid, stud[delnum].final, stud[delnum].quiz);
fclose(f);
remove("student.bin");
if ((f = fopen("student.bin", "ab+")) == NULL)
{
printf("파일이 열리지 않습니다\n");
exit(1);
}
for (int i = delnum; i <= num; i++)
{
stud[i] = stud[i + 1];
stud[i].num--;
}
for (int i = 1; i < num; i++)
fwrite(&stud[i], studsize, 1, f);
printf("삭제되었습니다\n");
}
void removal(FILE *f)
{
fclose(f);
remove("student.bin");
if ((f = fopen("student.bin", "ab+")) == NULL)
{
printf("파일이 열리지 않습니다\n");
exit(1);
}
printf("모든 레코드들이 삭제되었습니다\n");
}
void grade(FILE *f)
{
printf("학점:A(200이상),B(150이상),C(150미만)\n");
rewind(f);
student stud;
int cnt = 0;
int hap = 0;
char hakjum;
int readcnt = fread(&stud, studsize, 1, f);
if (readcnt == 0)
{
printhead();
printf("-----------------------------------------\n");
printf("모두 0명 입니다\n");
return;
}
printf("-----------------------------------------\n");
printf("%8s%15s%10s%8s%8s%8s%8s\n", "번호", "이름", "중간", "기말", "퀴즈", "합", "학점");
printf("-----------------------------------------\n");
while (!feof(f))
{
++cnt;
hap = stud.mid + stud.final + stud.quiz;
if (hap >= 200)
hakjum = 'A';
else if (hap >= 150)
hakjum = 'B';
else
hakjum = 'C';
printf("%6d%18s%8d%8d%8d%8d%8c\n", stud.num, stud.name, stud.mid, stud.final, stud.quiz, hap, hakjum);
fread(&stud, studsize, 1, f);
}
printf("-----------------------------------------\n");
printf("모두 %d명 입니다\n", cnt);
}
void printhead()
{
printf("-----------------------------------------\n");
printf("%8s%15s%10s%8s%8s\n", "번호", "이름", "중간", "기말", "퀴즈");
printf("-----------------------------------------\n");
}
파일처리 화이팅!
삭제함수 아래쪽은 건드리지 못했다.
블로그의 정보
OMIN
오민