본문 바로가기
c언어

c언어 이진 파일 읽고 쓰는 법과 버퍼에 대하여 알아보기

by 개발자 L 2023. 2. 16.
반응형

c언어 이진 파일 읽고 쓰는 법과 버퍼에 대하여 알아보기

네 안녕하세요, 이번 포스팅에서는 이진 파일을 읽고 쓰는 방법과 버퍼에 대하여 알아보려 합니다.

우리가 사용하는 파일의 종류는 크게 두 가지입니다.

  • 텍스트 파일
  • 이진 파일

이 중에 우리는 텍스트 파일에 대하여 먼저 알아보았고,

이제 이진 파일에 대하여 알아볼 것입니다.

텍스트 파일에 대한 부분은 제가 링크를 걸어두도록 하겠습니다.

이 부분을 참고하시면 감사하겠습니다.

 

2023.02.16 - [분류 전체 보기] - c언어 텍스트 파일 읽는 법과 쓰는 법 알아보기

 

c언어 텍스트 파일 읽는 법과 쓰는 법 알아보기

c언어 텍스트 파일 읽는 법과 쓰는 법 알아보기 네 안녕하세요, 이번 포스팅에서는 텍스트 파일 읽기와 쓰기에 대하여 알아보도록 하겠습니다. 우리가 일단 텍스트 파일을 열었다면 무언가를 작

funnycoderl.tistory.com

 

1. 이진 파일이란?

이진 파일은 텍스트 파일과는 다른 데이터가 직접 입력이 되어있는 파일입니다.

텍스트 파일은 컴퓨터가 쓰는 언어를

사람이 알아볼 수 있는 언어인 텍스트로 변환하여 저장을 한 데이터가 있는 파일이라면,

이진 파일은 그게 아니라 컴퓨터가 쓰는 언어인 2진수 그대로 저장이 되어있는 형태의 파일을 말합니다.

그러면 이러한 이진 파일의 장점과 단점은 무엇이 있을까요?

1 - 1. 이진 파일의 장점

일단 이진 파일의 장점이라 하면 변환을 거치지 않고 바로 저장을 한다는 점에서

시간 절약이 됩니다.

또한, 텍스트 파일에 비해서 그냥 일반 2진수 숫자 형식으로 되어있으며,

2진수는 보통 8자리의 숫자, 이를 '옥텟'이라고 하는데,

이 옥텟 한 개의 용량이 8비트 밖에 되지 않습니다.

하지만 텍스트의 경우는 가장 작은 용량이 영어 알파벳 한 개만 있는 1바이트,

다시 말하면 2진수 1 옥텟에 1이 가득 찬 것과 같은 용량이 최소 용량이라는 것입니다.

그렇기 때문에 상대적으로 메모리를 많이 잡아먹는 텍스트에 비해서

이진 파일은 메모리를 훨씬 덜 잡아먹어서 메모리 효율도 높습니다.

 

1 - 2. 이진 파일의 단점

하지만 이진 파일 역시 단점은 존재합니다.

일단 컴퓨터가 알아보는 언어로 저장이 되어있기 때문에 우리는 알아볼 수 없으며,

모니터와 프린터 역시 텍스트 파일만을 입출력하다 보니 이 둘로 출력하는 것도 불가능합니다.

그리고 이러한 표현 방식은 컴퓨터에 들어가는 부품을 어떤 것을 쓰느냐에 따라서 인코딩 형식이 다 달라서

아스키코드를 기반으로 하고 있는 텍스트와는 다르게 컴퓨터 간 이동도 힘들어서 이식성이 떨어집니다.

그렇기 때문에 이식성을 중요시한다면 텍스트 파일을 써야 하고,

시공간 효율을 중요시 한다면 이진 파일을 써야 합니다.

반응형

 

2. 이진 파일 읽고 쓰기

 

2 - 1. 이진 파일 쓰기

이번에는 이진 파일을 쓰는 방법에 대하여 알아보도록 하겠습니다.

이진 파일은 대량의 파일을 한 번에 받을 때 메모리 공간을 덜 차지하기 때문에 효율적입니다.

그럼 제가 코드를 한 번 짜보도록 하겠습니다.

#include <stdio.h>

#define SIZE 5

int main()
{
    int buffer[SIZE] = {10, 20, 30, 40, 50};
    FILE *fp = NULL;

    fp = fopen("binary.bin", "wb");

    if(fp == NULL)
    {
        fprintf(stderr, "binary.bin 파일을 열 수 없습니다.\n");

        return 1;
    }

    fwrite(buffer, sizeof(int), SIZE, fp); // SIZE 만큼의 항목을 fp로 저장

    fclose(fp);

    return 0;
}

이렇게 코드를 짜봤습니다.

그럼 결과를 보도록 하겠습니다.

코드 실행 전
코드 실행 후

보시면 코드 실행 전과 후에 차이가 보임을 알 수 있습니다.

'binary.bin'이라는 파일이 하나 생긴 걸 볼 수 있습니다.

그리고 이진 파일의 확장자명은 'bin'이라고 합니다.

그리고 아래의 표는 이진 파일의 모드입니다.

파일 모드 설명
rb 이진 파일 읽기 모드
wb 이진 파일 쓰기 모드
ab 이진 파일 추가 모드
rb+ 이진 파일 읽고 쓰기 모드
wb+ 이진 파일 쓰고 읽기 모드

그리고 텍스트 파일에서도, 그리고 이진 파일에서도 항상 쓰는 buffer라는 것이 눈에 보일 건데,

이 buffer는 파일에 기록할 데이터를 가지고 있는 메모리 블록의 시작 주소입니다.

그렇기 때문에 이 buffer를 읽어와서 포인터를 반환하는 원리로 데이터를 저장합니다.

 

2 - 2. 이진 파일 읽기

이진 파일을 이번에는 읽어보도록 하겠습니다.

이진 파일은 기본 에디터로 열면 이런 식으로 뜹니다.

이렇게 지원되지 않는 형식이라고 뜨는데,

기본적으로 IDE 프로그램 에디터의 경우에는 텍스트 데이터를 우선으로 하기 때문에 그렇습니다.

그래서 이번엔 이 파일을 열어서 파일의 데이터를 화면에 표시하는 코드를 작성해보려 합니다.

#include <stdio.h>

#define SIZE 5

int main()
{
    int buffer[SIZE];
    FILE *fp = NULL;

    fp = fopen("binary.bin", "rb");

    if(fp == NULL)
    {
        fprintf(stderr, "binary.bin 파일을 열 수 없습니다.\n");

        return 1;
    }

    fread(buffer, sizeof(int), SIZE, fp);

    for(int i=0; i< SIZE; i++)
    {
        printf("%d", buffer[i]);
    }

    printf("\n");

    fclose(fp);

    return 0;
}

이렇게 작성을 했습니다.

이진 데이터의 크기만큼 읽어오는 프로그램이고,

정수형 데이터를 불러올 겁니다.

그 이유는 제가 앞서 작성한 코드 속 데이터는 이진 데이터이기 때문입니다.

그럼 결과를 보도록 하겠습니다.

10 20 30 40 50

이렇게 결과가 잘 나온 것을 확인할 수 있습니다.

 

3. 버퍼링

우리가 지금까지 해왔던 스트림에는 기본적으로 버퍼(buffer)가 포함이 되어있습니다.

그 이유는 fopen() 함수 이용 시에 출력할 때 버퍼를 이용하기 때문입니다.

버퍼는 파일로부터 읽고 쓰는 데이터를 임시로 저장하는 장소이고, 메모리의 블록입니다.

그래서 버퍼가 존재한다면 이 버퍼 안에 먼저 저장이 되고, 이 버퍼가 다 채워졌을 때

디스크 파일에 그 내용을 기록합니다.

그리고 파일의 읽고 쓰는 것 모두 버퍼가 다 개입을 해서 관리를 합니다.

그렇게 하는 이유는 디스크에서 직접 데이터를 꺼내오는 것은 시간이 너무 오래 걸려서

그걸 방지하고자 버퍼를 씁니다.

하지만 이레적인 경우들이 있죠?

이런 경우들이 있습니다.

  • 버퍼를 비워야 하는 경우
  • 버퍼가 있으면 안 되는 경우

이제 이 둘에 대하여 알아보도록 하겠습니다.

 

3 - 1. 버퍼를 비워야 하는 경우

프로그램에 따라서 직접 하드웨어 장치에 써지도록 설계를 한 프로그램들이 있는데,

그럴 경우에는 버퍼에 저장이 되면 안 되기 때문에 버퍼를 비우는 함수를 써야 합니다.

버퍼를 비우는 함수는 fflush()인데, 이걸 쓰면 버퍼가 비워지고, 버퍼의 내용이 디스크에 직접 기록이 됩니다.

사용법은 이렇습니다.

fflush(fp);

항상 받을 때는 fp라는 파일 포인터를 이용해서 받습니다.

그리고 모드에 따라서 읽기 모드일 경우는 그냥 버퍼가 비워지고 아무런 일도 일어나지 않고,

쓰기 모드일 경우는 버퍼가 비워지면서 디스크에 기록이 됩니다.

 

3 - 2. 버퍼가 있으면 안 되는 경우

버퍼가 있으면 안되는 경우는 크게 두 가지입니다.

  • 장치나 파일 등을 직접 제어를 할 필요가 있는 경우
  • 대량의 이진 데이터를 처리(쓰기 및 읽기)하는 경우

그래서 이런 경우에는 오히려 버퍼가 걸림돌이 되기 때문에 버퍼가 없는 것이 좋습니다.

이럴 경우에는 setbuf()라는 함수를 쓰는데,

이런 식으로 쓰면 됩니다.

setbuf(fp, NULL);

여기서 버퍼 자리에 저렇게 NULL을 주게 되면 버퍼를 제거하겠다는 뜻이 됩니다.

하지만 버퍼가 없는 입출력을 하게 되면 시간이 매우 오래 걸려서 효율이 떨어지므로,

꼭 필요한 상황에만 할 것을 권장합니다.

 

여기까지 이진 파일을 읽고 쓰는 법에 대하여 알아보았는데요,

다음 포스팅에서는 임의 접근에 대하여 알아보도록 하겠습니다.

긴 글 읽어주신 독자분들께 진심으로 감사드립니다~

반응형

댓글