72.2 파일에서 구조체 읽기
이제 앞에서 생성한 data2.bin 파일(char, short, int, char 배열을 저장한 파일)의 내용을 읽어보겠습니다. 파일에서 구조체를 읽으려면 fread 함수를 사용합니다.
- fread(버퍼, 읽기크기, 읽기횟수, 파일포인터);
- size_t fread(void *_Buffer, size_t _ElementSize, size_t _ElementCount, FILE *_Stream);
- 성공한 읽기 횟수를 반환, 실패하면 지정된 읽기 횟수보다 작은 값을 반환
다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.
file_read_struct.c
#define _CRT_SECURE_NO_WARNINGS // fopen 보안 경고로 인한 컴파일 에러 방지 #include <stdio.h>> // fopen, fread, fclose 함수가 선언된 헤더 파일 #pragma pack(push, 1) // 1바이트 크기로 정렬 struct Data { char c1; // 1바이트 short num1; // 2바이트 int num2; // 4바이트 char s1[20]; // 20바이트 }; #pragma pack(pop) // 정렬 설정을 이전 상태(기본값)로 되돌림 int main() { struct Data d1; FILE *fp = fopen("data2.bin", "rb"); // 파일을 읽기/바이너리 모드(rb)로 열기 fread(&d1, sizeof(d1), 1, fp); // 파일의 내용을 읽어서 구조체 변수에 저장 printf("%c %d %d %s\n", d1.c1, d1.num1, d1.num2, d1.s1); // a 32100 2100000100 Hello, world! fclose(fp); // 파일 포인터 닫기 return 0; }
실행 결과
a 32100 2100000100 Hello, world!
먼저 파일에서 읽은 내용을 저장할 구조체를 정의합니다. 앞에서 data2.bin 파일에 1바이트 크기의 char, 2바이트 크기의 short, 4바이트 크기의 int, 20바이트 크기의 char 배열에 값을 넣어서 저장했으므로 파일에서 값을 읽을 때도 똑같은 구조체를 만들어줍니다. 또한, 구조체의 각 멤버 크기 그대로 읽을 수 있도록 1바이트 크기로 정렬합니다.
#pragma pack(push, 1) // 1바이트 크기로 정렬 struct Data { char c1; // 1바이트 short num1; // 2바이트 int num2; // 4바이트 char s1[20]; // 20바이트 }; #pragma pack(pop) // 정렬 설정을 이전 상태(기본값)로 되돌림
바이너리 파일을 읽어서 구조체에 저장할 때는 구조체 멤버의 크기뿐만 아니라 순서도 중요합니다. 만약 구조체 멤버의 순서가 달라진다면 값의 일부만 가져오거나 여러 개의 값을 묶어서 가져올 수도 있으므로 주의해야 합니다.
이제 fopen 함수로 data2.bin 파일을 읽기/바이너리 모드(rb)로 엽니다. 그리고 fread 함수의 버퍼는 구조체 변수의 주소 &d1, 읽기 크기는 구조체 크기, 읽기 횟수는 1을 넣어줍니다. 마지막에는 파일 포인터 fp를 넣습니다.
struct Data d1; FILE *fp = fopen("data2.bin", "rb"); // 파일을 읽기/바이너리 모드(rb)로 열기 fread(&d1, sizeof(d1), 1, fp); // 파일의 내용을 읽어서 구조체 변수에 저장
printf로 구조체 변수의 값을 출력해보면 앞에서 저장한 값이 출력됩니다. 특히 파일에는 값이 리틀 엔디언 방식으로 저장되어 있다 하더라도 printf 함수로 값을 출력해보면 사람이 읽을 수 있는 형태로 나오기 때문에 엔디언 문제는 걱정하지 않아도 됩니다.
printf("%c %d %d %s\n", d1.c1, d1.num1, d1.num2, d1.s1); // a 32100 2100000100 Hello, world!
즉, data2.bin 파일을 읽어서 구조체에 저장하면 다음과 같은 모양이 됩니다.
파일 읽기가 끝났다면 fclose 함수로 파일 포인터를 닫습니다.
fclose(fp); // 파일 포인터 닫기
지금까지 파일에서 구조체를 읽고 쓰는 방법을 배웠는데 리틀 엔디언 때문에 값이 뒤집혀서 알아보기가 조금 까다로웠습니다. 여기서는 파일에서 구조체를 읽고 쓸 때 반드시 구조체를 1바이트 크기로 정렬해야 된다는 점만 기억하면 됩니다.