C언어 입/출력 파일입출력 함수

    2018-02-10 04:11:09 작성

    feof

    파일의 끝에 도달한 경우 0이 아닌 값을 반환합니다.

    int feof(FILE * stream)

    파일의 끝을 확인할때 유용하게 사용되는 함수입니다.
    다음 예제는 파일을 복사하는 예제입니다.

    #include <stdio.h>
    
    int main(void) {
    	FILE * src = fopen("c:/sample/ezcode.txt", "rt"); // 원본
    	FILE * des = fopen("c:/sample/ezcode_copy.txt", "wt"); // 사본
    	char str[30];
    
    	if (src == NULL || des == NULL) {
    		puts("파일 읽기 실패");
    		return -1;
    	}
    
    	while (fgets(str, sizeof(str), src) != NULL) { // 한줄씩 읽어
    		fputs(str, des); // 한줄씩 쓴다.
    	}
    
    	if (feof(src) != 0) { // 파일을 끝까지 읽었는지 확인
    		puts("파일복사 완료!");
    	}
    	else {
    		puts("파일복사 실패!");
    	}
    	fclose(src);
    	fclose(des);
    	return 0;
    }


    feof는 파일을 끝까지 도달했는지 확인할때 유용한 함수입니다.


    fread, fwrite

    지금까지 텍스트모드에서 읽고 쓰기를 했습니다.
    fread 함수와 fwrite 함수는 바이너리 모드에서 입출력할때 사용하는 함수입니다.

    fread
    size_t fread(void * buffer, size_t size, size_t count, FILE * stream);

    fread 함수 호출 성공시 count를 반환하고, 실패 또는 파일 끝에 도달했을때에는 count보다 작은값을 반환합니다.

    int buf[20];
    fread((void*)buf, sizeof(int), 20, fp);

    fp(파일 포인터)로부터 sizeof(int)크기의 데이터를 20개 읽어 배열 buf에 저장하라는 의미입니다.


    fwrite
    size_t fwrite(const void * buffer, size_t size, size_t count, FILE * stream);

    fwrite 함수 호출 성공시 count를 반환하고, 실패시 count보다 작은 값을 반환합니다.

    int buf[5] = {1,2,3,4,5}
    fwrite((void*)buf, sizeof(int), 5, fp); 

    buf 배열에서 sizeof(int)크기씩 5개의 값을 fp(파일포인터)에 쓰라는 의미입니다.

    fread, fwrite 함수 모두
    1번째 인자를 void* 자료형으로 캐스팅하는데 void 포인터는 무엇이든지 가리킬수 있기 때문에 크기와 관계없이 char형이나 double형 자료형도 전달할 수 있습니다.
    2번째 인자는 하나의 값을 입출력할때의 자료형의 크기를 전달합니다.
    3번째 인자는 자료형 입출력할 자료형의 개수를 전달합니다.
    4번째 인자는 입출력 스트림을 지정합니다.

    다음 예제는 이름을 입력받아 바이너리 파일로 저장합니다.

    #include <stdio.h>
    #include <string.h>
    
    int main(void) {
    	FILE * fp = fopen("c:/sample/binary.dat", "wb"); // 바이너리 파일 생성
    	char name[20];
    
    	if (fp == NULL) {
    		puts("파일 읽기 실패");
    		return -1;
    	}
    
    	do {
    		printf("종료 END 이름입력 : ");
    		gets(name);
    		if (strncmp(name, "END", 3)) { // END 문자열이 아니면
    			fwrite((void*)name, sizeof(name), 1, fp); //파일에 기록한다
    		}
    		else {
    			puts("파일을 작성하였습니다.");
    			break;
    		}
    	} while (1);
    	fclose(fp);
    	return 0;
    }


    다음은 위에 작성된 파일을 읽어 들입니다.

    #include <stdio.h>
    
    int main(void) {
    	FILE * fp = fopen("c:/sample/binary.dat", "rb"); // 바이너리 파일 읽기
    	char name[20];
    
    	if (fp == NULL) {
    		puts("파일 읽기 실패");
    		return -1;
    	}
    
    	while (1) {
    		// 20byte 1개를 읽어들이지 못하면 탈출
    		if (fread((void*)name, sizeof(name), 1, fp) != 1) {
    			break;
    		}
    		puts(name);
    	}
    	fclose(fp);
    	return 0;
    }


    fread 함수와 fwrite 함수를 사용하면 byte단위로 입출력을 할수 있어 구조체 및 배열등을 입출력할때 편리합니다.


    fprintf, fscanf

    서식에 따른 데이터의 입출력을 할 수 있습니다.
    fprintf와 fscanf 함수는 첫번째 인자로 스트림을 지정하는것을 제외하고 printf, scanf와 동일하게 작동합니다.

    int fprintf ( FILE * stream, const char * format, ... );
    int fscanf ( FILE * stream, const char * format, ... );

    다음 예제는 구조체를 저장합니다.

    #include <stdio.h>
    
    typedef struct _person {
    	char name[10];
    	char gender;
    	int age;
    } Person;
    
    int main(void) {
    	FILE * fp = fopen("c:/sample/ezcode.txt", "wt");
    	Person person[3] = {
    		{"홍길동", 'M', 27},
    		{"임꺽정", 'M', 25},
    		{"황진이", 'F', 21}
    	};
    	int i;
    
    	if (fp == NULL) {
    		puts("파일 읽기 실패");
    		return -1;
    	}
    
    	for (i = 0; i < 3; i++) {
    		fprintf(fp, "%s %c %d\n", person[i].name, person[i].gender, person[i].age);
    	}
    	printf("파일을 저장하였습니다.\n");
    	fclose(fp);
    	return 0;
    }



    #include <stdio.h>
    
    typedef struct _person {
    	char name[10];
    	char gender;
    	int age;
    } Person;
    
    int main(void) {
    	FILE * fp = fopen("c:/sample/ezcode.txt", "rt");
    	Person person;
    
    	if (fp == NULL) {
    		puts("파일 읽기 실패");
    		return -1;
    	}
    
    	while (!feof(fp)) {
    		fscanf(fp, "%s %c %d\n", person.name, &person.gender, &person.age); // \n은 개행을 읽어 버립니다.
    		printf("%s %c %d\n", person.name, person.gender, person.age);
    	}
    
    	fclose(fp);
    	return 0;
    }


    scanf와 마찬가지로 공백을 구분하여 데이터를 읽어 각 변수에 저장합니다.


    연습문제

    1. 위에서 정의한 Person 구조체를 정의합니다.
    2. 사용자로부터 3개의 데이터를 입력받습니다.
    3. Person 데이터를 바이너리 파일로 저장합니다.
    4. 파일에서 Person 데이터를 읽어서 출력합니다.