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);
}
-