C 언어 파일 처리
파일 스트림과 파일 열기
프로그램이 파일에 데이터를 쓰거나 읽기 위해서는, 프로그램과 파일 사이에 연결 통로인 **Stream(스트림)**을 만들어야 한다. C 언어에서는 fopen() 함수를 사용하여 이 스트림을 생성하고 파일을 연다.
fopen() 함수
fopen() 함수는 지정된 파일을 특정 모드로 열어 파일 스트림을 생성하고, 이 스트림을 제어하는 데 필요한 정보가 담긴 FILE 구조체에 대한 포인터를 반환한다. fopen() 함수의 원형은 stdio.h 헤더 파일에 정의되어 있다.
-
함수 원형
FILE *fopen(const char *filename, const char *mode); -
인자
filename: 처리할 파일의 경로와 이름을 나타내는 문자열이다.mode: 파일을 어떤 방식으로 처리할지를 지정하는 문자열이다.
-
반환값
- 파일 열기에 성공하면 해당 파일의 정보를 담고 있는
FILE구조체를 가리키는 포인터를 반환한다. - 파일 열기에 실패하면
NULL을 반환한다.
- 파일 열기에 성공하면 해당 파일의 정보를 담고 있는
FILE은 stdio.h에 struct _iobuf로 정의된 구조체로, 파일 처리에 필요한 내부 정보를 관리한다.
파일 열기 및 닫기 예제
파일을 열 때는 fopen()의 반환값이 NULL인지 확인하여 파일 열기 성공 여부를 반드시 검사해야 한다. 파일 처리가 모두 끝난 후에는 fclose() 함수를 호출하여 스트림을 닫고 시스템 자원을 반환해야 한다.
#include <stdio.h>
FILE *fp;
char fname[] = "basic.txt";
// "w"(쓰기) 모드로 파일 열기 시도
if ((fp = fopen(fname, "w")) == NULL) {
printf("파일이 열리지 않습니다.\n"); // 실패 시 메시지 출력
} else {
// 파일 처리 작업 수행
// ...
fclose(fp); // 파일 닫기
}
파일 처리 모드
fopen() 함수의 두 번째 인자인 mode에 따라 파일의 동작 방식이 결정된다.
| 모드 | 의미 |
|---|---|
r | 읽기(read) 모드로 파일을 연다. 파일이 존재하지 않으면 에러가 발생한다. |
w | 쓰기(write) 모드로 파일을 연다. 파일이 없으면 새로 생성하고, 파일이 있으면 기존 내용은 모두 삭제하고 처음부터 쓴다. |
a | 추가 쓰기(append) 모드로 파일을 연다. 파일이 없으면 새로 생성하고, 파일이 있으면 내용의 가장 뒤에 데이터를 추가한다. |
r+ | 읽기와 쓰기 모드로 파일을 연다. 파일이 없으면 에러가 발생한다. |
w+ | 읽기와 쓰기 모드로 파일을 연다. 파일이 없으면 새로 생성하고, 파일이 있으면 기존 내용을 삭제한다. |
a+ | 읽기와 추가 쓰기 모드로 파일을 연다. 파일이 없으면 새로 생성한다. 읽기는 파일의 어느 위치에서나 가능하지만, 쓰기는 항상 파일 끝에 추가만 가능하다. |
파일 입출력 함수
서식화된 입출력: fprintf(), fscanf()
fprintf()와 fscanf() 함수는 printf, scanf와 유사하지만, 출력을 모니터가 아닌 지정된 파일 스트림에 하거나, 입력을 키보드가 아닌 파일 스트림으로부터 받는 점이 다르다.
-
함수 원형
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...); -
특징
- 첫 번째 인자로
FILE포인터를 받는다. stdio.h에 정의된 표준 스트림 키워드stdout,stdin을 첫 번째 인자로 사용하면 각각printf,scanf와 동일하게 동작한다.
- 첫 번째 인자로
| 표준 파일 | 키워드 | 기본 장치 |
|---|---|---|
| 표준 입력 | stdin | 키보드 |
| 표준 출력 | stdout | 모니터 |
| 표준 에러 | stderr | 모니터 |
문자열 입출력: fgets(), fputs()
파일에서 한 줄씩 문자열을 읽거나 쓸 때는 fgets()와 fputs()를 사용한다.
-
함수 원형
char *fgets(char *str, int n, FILE *stream);
int fputs(const char *str, FILE *stream); -
fgets()특징- 최대
n-1개의 문자를 읽어str에 저장한다. - 개행 문자(
\n)를 만나면 읽기를 중단하며, 이 개행 문자도 문자열의 일부로 함께 저장한다.
- 최대
-
fputs()특징str이 가리키는 문자열을stream에 쓴다.
문자 입출력: fgetc(), fputc()
파일에서 문자 하나를 읽거나 쓸 때는 fgetc()와 fputc()를 사용한다.
-
함수 원형
int fgetc(FILE *stream);
int fputc(int c, FILE *stream); -
특징
getc(),putc()와 기능적으로 동일하지만,fgetc/fputc는 함수이고getc/putc는 매크로로 구현되어 있다.- 표준 입출력 함수인
getchar()와putchar()는getc(stdin)와putc(c, stdout)을 이용한 매크로다.
파일 상태 검사
feof()와 ferror()
feof(): 파일의 끝(End-Of-File)에 도달했는지 검사하는 함수이다. 파일 포인터가 파일의 끝을 가리키면 0이 아닌 값(true)을, 아니면 0(false)을 반환한다.ferror(): 파일 입출력 과정에서 오류가 발생했는지 검사하는 함수이다. 오류가 발생했다면 0이 아닌 값(true)을, 아니면 0(false)을 반환한다.
파일의 끝(EOF) 검사 방법
파일의 모든 내용을 읽기 위해서는 파일의 끝을 정확히 감지해야 한다.
-
입력 함수의 반환값 검사 (권장)
fgetc(),fscanf()와 같은 파일 입력 함수들은 파일의 끝에 도달하거나 오류가 발생하면EOF(-1)라는 특별한 값을 반환한다. 이 반환값을 직접 검사하는 것이 가장 안정적이고 정확한 방법이다.-
fgetc()사용 예시int ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
} -
fscanf()사용 예시char name[30];
int score1, score2;
// fscanf는 성공적으로 읽은 항목의 수를 반환한다.
while (fscanf(fp, "%s %d %d", name, &score1, &score2) != EOF) {
printf("%s %d %d\n", name, score1, score2);
}
-
-
feof()함수 사용feof()함수는 직전의 파일 작업이 파일의 끝에 도달했는지를 알려준다. 따라서while(!feof(fp))와 같이 반복문의 조건으로 직접 사용하는 것은 권장되지 않는다. 왜냐하면 마지막 데이터를 성공적으로 읽은 후에도feof()는 false를 반환하고, 루프가 한 번 더 실행되어 마지막 데이터가 중복 처리될 수 있기 때문이다.-
잘못될 수 있는
feof()사용 예시// 이 코드는 파일의 마지막 줄을 두 번 처리할 수 있다.
while (!feof(fp)) {
fscanf(fp, "%s %d %d", name, &score1, &score2);
printf("%s %d %d\n", name, score1, score2);
}
-