Skip to main content

C 언어 이진 파일 처리

텍스트 파일과 이진 파일의 차이

파일은 크게 텍스트 파일과 이진 파일로 나눌 수 있다.

  • 텍스트 파일 (Text File) 텍스트 파일은 사람이 텍스트 편집기로 내용을 쉽게 읽고 수정할 수 있는 파일이다. 파일의 모든 내용은 문자 코드(예: 아스키 코드) 값으로 저장된다. 예를 들어, fprintf() 함수를 사용해 정수 10을 파일에 저장하면, 숫자 10이 저장되는 것이 아니라 문자 '1'과 '0'에 해당하는 아스키 코드(0x31, 0x30)가 각각 1바이트씩 저장된다.
  • 이진 파일 (Binary File) **Binary File(이진 파일)**은 C 언어의 자료형을 메모리에 저장된 바이트 형태 그대로 파일에 저장한다. 따라서 일반 텍스트 편집기로는 그 내용을 정확히 확인할 수 없다. 예를 들어, fwrite() 함수를 사용해 4바이트 정수 10을 저장하면, 메모리에 있는 4바이트 0x0000000A 값이 그대로 파일에 저장된다. 실행 파일(.exe)이 대표적인 이진 파일이다.

이진 파일 입출력 함수: fwrite()fread()

이진 파일의 데이터를 처리하기 위해서는 fwrite()fread() 함수를 사용해야 한다. 이 함수들은 데이터를 바이트 단위의 블록으로 취급하여 입출력을 수행한다.

  • 함수 원형

    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

    이진 파일에 기록된 데이터는 fread()를 사용해 읽어야 원래의 자료형을 그대로 유지할 수 있다.

  • 인자와 반환값

    • 인자
      1. ptr: 입출력할 데이터 블록의 메모리 주소 (void* 타입으로 모든 포인터 수용).
      2. size: 데이터 단위 하나(블록)의 바이트 크기.
      3. nmemb: 입출력할 데이터 단위(블록)의 개수.
      4. stream: 파일 포인터.
    • 반환값: 성공적으로 처리된 데이터 단위(블록)의 개수를 반환한다.
  • 이진 파일 모드 이진 파일을 처리하려면 fopen() 함수를 호출할 때 모드 문자열에 b를 추가해야 한다 (예: "rb", "wb", "ab", "rb+", "wb+", "ab+").

구조체 이진 파일 입출력 예제

구조체와 같은 복합 자료형도 fwrite()fread()를 이용하면 손쉽게 파일에 저장하고 읽어올 수 있다.

// 학생 정보를 담는 구조체
typedef struct {
char name[20];
double score[2];
} Student;

Student list[3]; // 저장할 데이터
Student alist[3]; // 읽어올 데이터
FILE *fp;

// 사용자로부터 학생 정보 3개를 입력받는다고 가정
// ...

// 1. 이진 파일 쓰기
fp = fopen("student.bin", "wb"); // 쓰기 모드로 이진 파일 열기
if (fp == NULL) { /* 에러 처리 */ }
// list 배열의 내용을 파일에 한 번에 쓰기
fwrite(list, sizeof(Student), 3, fp);
fclose(fp);

// 2. 이진 파일 읽기
fp = fopen("student.bin", "rb"); // 읽기 모드로 이진 파일 열기
if (fp == NULL) { /* 에러 처리 */ }
// 파일의 내용을 alist 배열로 한 번에 읽기
fread(alist, sizeof(Student), 3, fp);
fclose(fp);

// 3. 읽어온 내용 확인
for(int i = 0; i < 3; i++) {
printf("%s %lf %lf\n", alist[i].name, alist[i].score[0], alist[i].score[1]);
}

파일 위치 제어와 임의 접근 (Random Access)

파일을 열면, 파일 내의 현재 위치를 가리키는 내부적인 **File Position Pointer(파일 위치 포인터)**가 생성된다. 이 포인터는 파일의 시작점으로부터 몇 바이트 떨어져 있는지를 나타내는 값으로, 일반적으로 long 자료형으로 취급한다. 데이터를 읽거나 쓰면 이 포인터는 작업한 바이트만큼 자동으로 뒤로 이동한다.

**Random Access(임의 접근)**는 이 파일 위치 포인터를 원하는 위치로 자유롭게 이동시켜 파일의 특정 부분에 직접 접근하는 것을 의미한다.

fseek() 함수

fseek() 함수는 파일 위치 포인터를 지정된 위치로 이동시키는 핵심 함수이다.

  • 함수 원형:

    int fseek(FILE *stream, long offset, int whence)
  • 인자

    • stream: 파일 포인터.

    • offset: whence 기준점으로부터 이동할 거리(바이트). 양수는 뒤로, 음수는 앞으로 이동을 의미한다.

    • whence: 이동의 기준이 되는 위치.

whence 기호 상수의미
SEEK_SET0파일의 시작 위치
SEEK_CUR1파일의 현재 위치
SEEK_END2파일의 끝 위치
  • 호출 예시

    • fseek(fp, 100L, SEEK_SET); : 파일 시작점에서 100바이트 위치로 이동한다.

    • fseek(fp, 50L, SEEK_CUR); : 현재 위치에서 50바이트 뒤로 이동한다.

    • fseek(fp, -100L, SEEK_END); : 파일 끝에서 100바이트 앞으로 이동한다.

기타 위치 관련 함수

  • long ftell(FILE *stream): 현재 파일 위치 포인터의 값을 반환한다.

  • void rewind(FILE *stream): 파일 위치 포인터를 파일의 시작점(offset 0)으로 되돌린다.

파일 관리 함수

stdio.h 헤더 파일에는 파일을 직접 관리하는 함수들도 정의되어 있다.

기능함수 원형
파일 삭제int remove(const char *filename)
파일 이름 변경int rename(const char *old_filename, const char *new_filename)
  • remove(): 지정된 파일을 삭제한다.

  • rename(): 파일의 이름을 변경한다.