C 기본 문법 – 파일 입출력 – 3편: 바이너리 파일 입출력 완전 정복
안녕하세요, 여러분! 😄
이번 시간에는 C 언어 파일 입출력 중에서 한 단계 더 나아간 주제, 바로 바이너리 파일 입출력에 대해 배워볼 거예요!
📂 우리가 지금까지 배운 텍스트 파일은 사람이 읽기 좋았지만,
속도와 효율성 면에서는 바이너리 파일이 훨씬 뛰어나답니다!
바이너리 파일은 마치 압축된 데이터 상자처럼,
필요한 정보를 빠르게 주고받는 데 아주 유용하죠!
자, 이제 함께 이 강력한 기능을 배워볼까요? 🚀
1. 바이너리 파일이란?
- 텍스트 파일: 사람이 읽을 수 있는 문자 데이터 (
printf
,scanf
등 사용) - 바이너리 파일: 컴퓨터가 이해하는 0과 1로 직접 저장되는 데이터
예를 들어 정수 100을 텍스트로 저장하면 '1'
, '0'
, '0'
→ 3바이트 사용하지만
바이너리로 저장하면 4바이트(int)
그대로 저장 → 더 빠르고 압축됨
🎯 바이너리 파일은 우리가 못 읽지만, 프로그램 간 빠른 데이터 교환에 매우 유리해요!
2. 사용 함수: fread()
와 fwrite()
함수 | 설명 |
---|---|
fwrite(ptr, size, count, stream) |
메모리에서 파일로 데이터 저장 |
fread(ptr, size, count, stream) |
파일에서 메모리로 데이터 불러오기 |
ptr
: 읽거나 쓸 데이터의 주소size
: 자료형의 크기 (sizeof(int)
등)count
: 요소 개수stream
:FILE*
포인터
3. 파일 열기 모드
바이너리 파일을 열 때는 모드 뒤에 "b"
를 붙여야 합니다.
모드 | 설명 |
---|---|
"rb" |
읽기 전용 (binary) |
"wb" |
쓰기 전용 (기존 내용 삭제) |
"ab" |
추가 쓰기 (파일 끝에 추가) |
"rb+" , "wb+" , "ab+" |
읽기/쓰기 겸용 |
💡 Windows에서는
b
를 붙여야 줄바꿈 자동 변환 없이 바이너리 그대로 처리돼요!
4. 정수 배열을 바이너리로 저장
#include <stdio.h>
int main() {
FILE *fp = fopen("data.bin", "wb");
int arr[5] = {10, 20, 30, 40, 50};
if (fp == NULL) {
printf("파일 열기 실패!
");
return 1;
}
fwrite(arr, sizeof(int), 5, fp);
fclose(fp);
printf("바이너리 파일로 저장 완료!
");
return 0;
}
💾 메모리 속 데이터를 통째로 파일로 내보내는 방식이에요!
5. 바이너리 파일에서 배열 불러오기
#include <stdio.h>
int main() {
FILE *fp = fopen("data.bin", "rb");
int arr[5];
if (fp == NULL) {
printf("파일 열기 실패!
");
return 1;
}
fread(arr, sizeof(int), 5, fp);
fclose(fp);
for (int i = 0; i < 5; i++) {
printf("읽은 값: %d
", arr[i]);
}
return 0;
}
🧠
fread()
는 파일 내용을 그대로 메모리에 복원해줍니다!
6. 구조체를 바이너리로 저장하기
바이너리 파일의 진가는 구조체 저장에서 빛을 발합니다!
#include <stdio.h>
#include <string.h>
typedef struct {
char name[20];
int age;
} Person;
int main() {
FILE *fp = fopen("person.dat", "wb");
Person p = {"홍길동", 30};
if (fp == NULL) {
printf("파일 열기 실패!
");
return 1;
}
fwrite(&p, sizeof(Person), 1, fp);
fclose(fp);
printf("구조체 저장 완료!
");
return 0;
}
🎯 메모리에 있는 구조체 내용을 그대로 파일에 쓰는 거예요!
7. 구조체 불러오기
#include <stdio.h>
typedef struct {
char name[20];
int age;
} Person;
int main() {
FILE *fp = fopen("person.dat", "rb");
Person p;
if (fp == NULL) {
printf("파일 열기 실패!
");
return 1;
}
fread(&p, sizeof(Person), 1, fp);
fclose(fp);
printf("이름: %s
", p.name);
printf("나이: %d
", p.age);
return 0;
}
😲 마치 타임머신처럼 메모리 상태를 복구하는 느낌이죠?
8. fread()
와 fwrite()
의 반환값
- 성공한 요소 개수를 반환합니다.
- 실패하면 요소 수가 다를 수 있음
size_t written = fwrite(arr, sizeof(int), 5, fp);
if (written != 5) {
printf("쓰기 오류 발생!
");
}
⚠️ 항상 결과를 확인해서 오류를 방지해야 해요!
✅ 바이너리 파일 입출력 요약
함수 | 역할 | 특징 |
---|---|---|
fwrite(ptr, size, count, stream) |
파일에 데이터 쓰기 | 빠르고 효율적 |
fread(ptr, size, count, stream) |
파일에서 데이터 읽기 | 형 변환 불필요 |
"wb" , "rb" 등 |
파일 모드 | 반드시 "b" 포함 |
구조체 저장 | 구조체 전체 저장 가능 | 직렬화 불필요 |
⚠️ 주의할 점 정리
항목 | 주의사항 |
---|---|
이식성 문제 | 시스템마다 구조체 정렬, 엔디안(Endian)이 다를 수 있음 |
NULL 체크 | 파일 열기 실패 시 반드시 예외 처리 |
데이터 일관성 | sizeof 크기가 정확히 일치해야 함 |
데이터 손상 | 잘못된 fread() 크기 → 이상한 값 읽힘 |
포인터 저장 금지 | 구조체에 포인터가 포함된 경우 직접 저장 불가 |
마무리하며 💬
바이너리 파일은 속도와 용량 면에서 최강입니다!
특히 많은 데이터를 구조체나 배열로 저장할 때는 텍스트보다 훨씬 강력한 무기가 되죠.
🎯 텍스트 파일이 수첩이라면,
바이너리 파일은 하드디스크에 압축 저장된 ZIP 파일 같은 존재예요!
빠르게, 효율적으로, 그리고 깔끔하게 데이터를 주고받을 수 있습니다.
다음 편에서는 **파일 포인터 위치 이동(fseek, ftell)**을 통해
좀 더 유연하게 파일을 다루는 방법을 알려드릴게요!
계속해서 열공하는 여러분을 응원합니다~ 💻🔥