본문으로 건너뛰기

C 언어 파일 처리

파일 스트림과 파일 열기

프로그램이 파일에 데이터를 쓰거나 읽기 위해서는, 프로그램과 파일 사이에 연결 통로인 **Stream(스트림)**을 만들어야 한다. C 언어에서는 fopen() 함수를 사용하여 이 스트림을 생성하고 파일을 연다.

fopen() 함수

fopen() 함수는 지정된 파일을 특정 모드로 열어 파일 스트림을 생성하고, 이 스트림을 제어하는 데 필요한 정보가 담긴 FILE 구조체에 대한 포인터를 반환한다. fopen() 함수의 원형은 stdio.h 헤더 파일에 정의되어 있다.

  • 함수 원형

    FILE *fopen(const char *filename, const char *mode);
  • 인자

    • filename: 처리할 파일의 경로와 이름을 나타내는 문자열이다.
    • mode: 파일을 어떤 방식으로 처리할지를 지정하는 문자열이다.
  • 반환값

    • 파일 열기에 성공하면 해당 파일의 정보를 담고 있는 FILE 구조체를 가리키는 포인터를 반환한다.
    • 파일 열기에 실패하면 NULL을 반환한다.

FILEstdio.hstruct _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) 검사 방법

파일의 모든 내용을 읽기 위해서는 파일의 끝을 정확히 감지해야 한다.

  1. 입력 함수의 반환값 검사 (권장) 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);
      }
  2. 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);
      }