C 기본 문법 – 파일 입출력 – 3 – 바이너리 파일 입출력

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)**을 통해
좀 더 유연하게 파일을 다루는 방법을 알려드릴게요!

계속해서 열공하는 여러분을 응원합니다~ 💻🔥

답글 남기기