바이너리 I/O

바이너리 파일 형식 저장

struct를 그대로 write하면 빠르지만, padding, endian, 정렬, 컴파일러 차이, 버전 변경 때문에 다른 환경에서 읽기 어려워질 수 있다. 안정적인 바이너리 I/O는 signature, version, length, endian 규칙을 명시한 format을 먼저 정한다.

01

헤더 정의

magic signature, format version, endian marker, payload 길이를 먼저 쓴다.

파일을 열자마자 형식을 식별한다
02

필드 직렬화

정수 크기, 부호, byte order, 문자열 길이를 고정해 하나씩 기록한다.

struct 통째 쓰기는 내부 padding을 포함한다
03

읽기 검증

read가 요청한 byte 수를 모두 채웠는지 확인하고 실패하면 상태를 버린다.

EOF 중간 파일은 정상 데이터가 아니다
04

버전 분기

새 필드가 추가되면 version에 따라 기본값, skip, migration 경로를 둔다.

오래된 파일을 읽을지 정책이 필요하다
05

무결성 확인

checksum, record count, length prefix로 잘린 파일과 손상 파일을 구분한다.

조용한 잘못된 읽기가 가장 위험하다
ios::binary
텍스트 변환 방지 줄바꿈 변환 없이 byte 그대로 읽고 쓰도록 파일을 연다.
Windows 텍스트 모드 차이를 피한다
endian
byte 순서 고정 파일 형식의 표준 순서를 정하고 읽을 때 변환한다.
동일 CPU에서만 쓸 파일인지 먼저 묻는다
padding
메모리 배치 누락 필드별로 쓰면 컴파일러 정렬 차이에 덜 의존한다.
packed struct는 해결책이 아니라 제약이다
version
형식 진화 header version으로 읽기 분기를 두고 호환 범위를 명시한다.
필드 추가는 읽기 코드 변경을 요구한다

파일 처리 확인

길이 확인 write와 read 결과 byte 수가 기대와 같은지 매번 확인한다.
교차 환경 다른 OS, compiler, endian 환경을 고려해야 하는 파일인지 판단한다.
손상 파일 잘린 파일, version 불일치, checksum 실패를 안전하게 거부하는지 테스트한다.