C++ I/O 및 파일 조작 - 5. 바이너리 파일 입출력 (Binary File I/O)

2025. 3. 30. 00:44프로그래밍 언어/C++

 

📘 5. 바이너리 파일 입출력 (Binary File I/O)

바이너리 파일(Binary File)은 사람이 읽을 수 있는 텍스트 형태가 아닌, 메모리에 저장된 그대로의 이진 데이터 형식으로 저장되는 파일입니다.
C++에서는 바이너리 데이터를 읽고 쓸 때 std::ios::binary 모드를 명시하여 파일을 열고, read()와 write() 함수를 통해 처리합니다.


✅ 바이너리 모드로 파일 열기

바이너리 파일을 열기 위해서는 std::ios::binary 플래그를 사용해야 합니다.

#include <fstream>

std::ofstream fout("data.bin", std::ios::binary);  // 쓰기용 이진 파일
std::ifstream fin("data.bin", std::ios::binary);   // 읽기용 이진 파일

📌 주의: 바이너리 모드 없이 열면 개행 문자 등 일부 데이터가 자동 변환될 수 있어, 정확한 이진 데이터 저장/복원이 어려워질 수 있습니다.


✅ 바이너리 데이터 읽기 및 쓰기

write()와 read() 함수는 메모리의 raw 데이터를 그대로 파일로 기록하거나, 파일에서 메모리로 그대로 불러옵니다.

#include <fstream>

int value = 123;

// 쓰기
std::ofstream fout("data.bin", std::ios::binary);
fout.write(reinterpret_cast<char*>(&value), sizeof(value));
fout.close();

// 읽기
std::ifstream fin("data.bin", std::ios::binary);
int readValue;
fin.read(reinterpret_cast<char*>(&readValue), sizeof(readValue));
fin.close();

📌 reinterpret_cast<char*>는 포인터 타입을 char*로 변환하여 바이트 단위로 처리하게 만듭니다.


✅ 구조체를 바이너리 파일에 저장하는 예제

구조체와 같은 복합 데이터도 바이너리 방식으로 저장하면 편리하게 관리할 수 있습니다.

#include <iostream>
#include <fstream>

struct Student {
    char name[20];
    int score;
};

int main() {
    Student s = {"Alice", 90};

    std::ofstream fout("student.dat", std::ios::binary);
    if (!fout) {
        std::cerr << "파일을 열 수 없습니다." << std::endl;
        return 1;
    }

    fout.write(reinterpret_cast<char*>(&s), sizeof(s));
    fout.close();

    // 읽기 확인
    Student s2;
    std::ifstream fin("student.dat", std::ios::binary);
    fin.read(reinterpret_cast<char*>(&s2), sizeof(s2));
    fin.close();

    std::cout << "이름: " << s2.name << ", 점수: " << s2.score << std::endl;

    return 0;
}

📌 구조체를 이진 파일에 저장할 때는 포인터, 동적 할당, std::string 같은 동적 객체가 포함되지 않도록 주의해야 합니다.
이러한 필드가 포함된 경우 직렬화(Serialization) 기법이 필요합니다.


✅ 텍스트 모드와의 차이점 요약

항목 텍스트 모드 바이너리 모드
개행 처리 \n → 운영체제에 따라 자동 변환 개행 문자도 1바이트 데이터로 그대로 저장
저장 형식 사람이 읽을 수 있는 문자열 형태 메모리 상태 그대로 저장
용도 로그, 설정 파일 등 이미지, 구조체, 고속 처리 데이터
처리 방식 <<, >>, getline() 등 read(), write()

✅ 사용 시 주의사항

  • 이진 데이터는 사람이 읽을 수 없으며, 디버깅도 어려우므로 데이터를 구조화해서 사용해야 합니다.
  • 바이너리 파일은 시스템(운영체제, 아키텍처 등)에 따라 엔디안(Endian) 문제정렬(Padding) 문제가 발생할 수 있습니다.
  • 이식성이 필요한 경우, 플랫폼 독립적인 바이너리 포맷 또는 직렬화 라이브러리 (예: protobuf)를 사용하는 것이 좋습니다.