고급 C 프로그래밍 – 파일 처리와 디렉터리 다루기 – 2편: 바이너리 파일 입출력
안녕하세요, C 언어 마스터를 향해 한 걸음씩 나아가는 여러분! 😊
오늘은 파일 처리 중에서도 조금 더 고급스럽고 실용적인 바이너리 파일 입출력에 대해 알아보겠습니다.
💾 바이너리 파일은 텍스트가 아닌 이진 데이터로 저장돼요.
마치 암호화된 문서처럼 보일 수 있지만, 사실은 가장 정확하고 빠른 방식으로 데이터를 저장하는 방법이랍니다!
텍스트 파일과는 다르게 문자 해석이 필요 없고,
숫자, 구조체, 이미지, 사운드, 게임 저장 데이터 등 다양한 포맷에서 쓰이는 핵심 기술이에요!
1. 바이너리 파일이란?
-
텍스트 파일은 사람이 읽을 수 있도록 인코딩된 문자 데이터를 저장
-
바이너리 파일은 0과 1의 비트 데이터를 그대로 저장
→ 사람은 이해 못 해도, 컴퓨터는 더 빠르고 정확하게 처리 가능!
예시
파일 형태
내용 예시
텍스트 파일
"홍길동, 30"
바이너리 파일
0x48 0x6F 0x6E ...
(인코딩된 형태)
📌 C 언어에서는 구조체나 정수형 데이터를 그대로 디스크에 저장할 수 있어요!
2. 바이너리 파일 열기
바이너리 파일을 열기 위해서는 fopen()
함수에서 모드 뒤에 ‘b’를 붙여야 합니다.
열기 모드 요약
모드
설명
"rb"
읽기 (바이너리)
"wb"
쓰기 (기존 내용 삭제)
"ab"
추가 쓰기
"rb+"
읽기/쓰기
"wb+"
읽기/쓰기 (초기화됨)
3. fread()
와 fwrite()
함수
함수 설명
c복사편집size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
-
ptr
: 데이터를 읽거나 쓸 메모리 주소 -
size
: 데이터 한 개의 크기 (예:sizeof(int)
) -
count
: 데이터 개수 -
반환값: 실제 읽거나 쓴 요소의 수
-
-
4. 예제 1 – 정수 배열 저장하고 불러오기
c복사편집#include <stdio.h>
int main() {
int data[5] = {10, 20, 30, 40, 50};
// 파일에 저장
FILE *fp = fopen("binary.dat", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
fwrite(data, sizeof(int), 5, fp);
fclose(fp);
// 파일에서 읽기
int readData[5] = {0};
fp = fopen("binary.dat", "rb");
fread(readData, sizeof(int), 5, fp);
fclose(fp);
// 출력
for (int i = 0; i < 5; i++) {
printf("readData[%d] = %d
", i, readData[i]);
}
return 0;
}
✅ 파일에는
10 20 30 40 50
이 이진 형태로 저장되어
사람이 보면 깨져 보이지만, 컴퓨터는 정확히 읽어옵니다!
5. 예제 2 – 구조체를 바이너리 파일에 저장하기
c복사편집#include <stdio.h>
typedef struct {
char name[20];
int age;
} Person;
int main() {
Person p1 = {"홍길동", 30};
FILE *fp = fopen("person.dat", "wb");
fwrite(&p1, sizeof(Person), 1, fp);
fclose(fp);
// 다시 읽기
Person p2;
fp = fopen("person.dat", "rb");
fread(&p2, sizeof(Person), 1, fp);
fclose(fp);
printf("이름: %s, 나이: %d
", p2.name, p2.age);
return 0;
}
🧠 구조체 통째로 저장하고 불러오는 건 텍스트 방식보다 훨씬 효율적이에요!
6. 바이너리 파일과 텍스트 파일의 차이점
항목
텍스트 파일
바이너리 파일
저장 방식
사람이 읽을 수 있음
기계용 이진 코드
크기
비교적 큼 (문자 인코딩 포함)
작음 (원 데이터 그대로 저장)
속도
느릴 수 있음 (형식 파싱 필요)
빠름
예시
.txt
, .csv
, .html
.dat
, .bin
, .exe
용도
로그, 설정, 간단한 데이터
이미지, 사운드, 구조체, 게임 데이터
7. 파일의 끝 확인: feof()
c복사편집while (!feof(fp)) {
fread(&data, sizeof(int), 1, fp);
}
하지만
feof()
는 읽은 뒤에야 EOF를 감지하므로,
반환값 체크가 더 정확해요!
c복사편집while (fread(&data, sizeof(int), 1, fp) == 1) {
// 처리
}
8. 주의해야 할 점
주의사항
설명
구조체 정렬 문제
컴파일러마다 구조체 내부 패딩 다를 수 있음 (#pragma pack
참고)
이식성
CPU 아키텍처가 다르면 저장된 바이너리 해석이 다를 수 있음
텍스트 에디터로 열면 깨짐
의도된 현상! 사람이 읽을 수 없음
경로 오류
상대 경로 or 절대 경로 확인 필요
fread()
는 반환값 체크 필수
읽은 데이터 개수로 오류 여부 판단
9. 비유로 이해하는 바이너리 파일
-
텍스트 파일: 마치 사람이 읽을 수 있는 설명서
-
바이너리 파일: 기계가 즉시 사용할 수 있는 부품 도면
🎯 “텍스트는 이해하기 쉽고, 바이너리는 처리하기 쉽다!”
✅ 요약 정리
함수
역할
fopen("파일", "wb"/"rb")
바이너리 파일 열기
fwrite(ptr, size, count, fp)
메모리 → 파일
fread(ptr, size, count, fp)
파일 → 메모리
fclose(fp)
파일 닫기
feof(fp)
파일 끝(EoF) 확인
마무리하며 💬
바이너리 파일 입출력은 성능과 효율성이 중요한 시스템에서 꼭 필요한 기술입니다.
게임 저장 데이터, 이미지 처리, 센서 로그 저장 등
정밀하고 빠른 처리가 필요할 때 꼭 사용되죠!
🎯 “눈에 보이지 않아도,
가장 빠르고 정밀하게 일하는 형식,
그것이 바이너리입니다.”
다음 시간에는 디렉터리 탐색, 폴더 생성, 파일 목록 조회 같은
디렉터리 조작 기술을 배워보겠습니다.
실제 파일 시스템과 소통하는 방법을 함께 익혀봐요! 🗂️📁💻