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()
를 사용해 읽어야 원래의 자료형을 그대로 유지할 수 있다. -
인자와 반환값
- 인자
ptr
: 입출력할 데이터 블록의 메모리 주소 (void*
타입으로 모든 포인터 수용).size
: 데이터 단위 하나(블록)의 바이트 크기.nmemb
: 입출력할 데이터 단위(블록)의 개수.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_SET | 0 | 파일의 시작 위치 |
SEEK_CUR | 1 | 파일의 현재 위치 |
SEEK_END | 2 | 파일의 끝 위치 |
-
호출 예시
-
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()
: 파일의 이름을 변경한다.